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 | |
15 | namespace dart { |
16 | |
17 | class IsolateGroup; |
18 | class 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 | |
101 | class ObjectPtr { |
102 | public: |
103 | OBJECT_POINTER_CORE_FUNCTIONS(ObjectPtr, tagged_pointer_) |
104 | |
105 | UntaggedObject* untag() const { |
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)); } |
111 | CLASS_LIST(DEFINE_IS_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 | } |
127 | CLASS_LIST_TYPED_DATA(DEFINE_IS_CID) |
128 | #undef DEFINE_IS_CID |
129 | |
130 | #define DEFINE_IS_CID(clazz) \ |
131 | bool IsFfi##clazz() const { return ((GetClassId() == kFfi##clazz##Cid)); } |
132 | CLASS_LIST_FFI(DEFINE_IS_CID) |
133 | #undef DEFINE_IS_CID |
134 | |
135 | bool IsStringInstance() const { return IsStringClassId(index: GetClassId()); } |
136 | bool IsRawNull() const { return GetClassId() == kNullCid; } |
137 | bool IsDartInstance() const { |
138 | return (!IsHeapObject() || !IsInternalOnlyClassId(index: GetClassId())); |
139 | } |
140 | bool IsFreeListElement() const { |
141 | return ((GetClassId() == kFreeListElement)); |
142 | } |
143 | bool IsForwardingCorpse() const { |
144 | return ((GetClassId() == kForwardingCorpse)); |
145 | } |
146 | bool IsPseudoObject() const { |
147 | return IsFreeListElement() || IsForwardingCorpse(); |
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 | |
210 | ObjectPtr() : tagged_pointer_(0) {} |
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 |
228 | return tagged_pointer_ & kHeapBaseMask; |
229 | } |
230 | |
231 | protected: |
232 | uword untagged_pointer() const { |
233 | ASSERT(IsHeapObject()); |
234 | return tagged_pointer_ - kHeapObjectTag; |
235 | } |
236 | |
237 | uword tagged_pointer_; |
238 | }; |
239 | |
240 | // Needed by the printing in the EXPECT macros. |
241 | #if defined(DEBUG) || defined(TESTING) |
242 | inline 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 | |
248 | template <typename T, typename Enable = void> |
249 | struct is_uncompressed_ptr : std::false_type {}; |
250 | template <typename T> |
251 | struct is_uncompressed_ptr< |
252 | T, |
253 | typename std::enable_if<std::is_base_of<ObjectPtr, T>::value, void>::type> |
254 | : std::true_type {}; |
255 | template <typename T, typename Enable = void> |
256 | struct is_compressed_ptr : std::false_type {}; |
257 | |
258 | template <typename T, typename Enable = void> |
259 | struct base_ptr_type { |
260 | using type = |
261 | typename std::enable_if<is_uncompressed_ptr<T>::value, ObjectPtr>::type; |
262 | }; |
263 | |
264 | #if !defined(DART_COMPRESSED_POINTERS) |
265 | typedef ObjectPtr CompressedObjectPtr; |
266 | #define DEFINE_COMPRESSED_POINTER(klass, base) \ |
267 | typedef klass##Ptr Compressed##klass##Ptr; |
268 | #else |
269 | class CompressedObjectPtr { |
270 | public: |
271 | OBJECT_POINTER_CORE_FUNCTIONS(CompressedObjectPtr, compressed_pointer_) |
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 | |
279 | ObjectPtr Decompress(uword heap_base) const { |
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 | |
298 | template <typename T> |
299 | struct is_compressed_ptr< |
300 | T, |
301 | typename std::enable_if<std::is_base_of<CompressedObjectPtr, T>::value, |
302 | void>::type> : std::true_type {}; |
303 | template <typename T> |
304 | struct base_ptr_type< |
305 | T, |
306 | typename std::enable_if<std::is_base_of<CompressedObjectPtr, T>::value, |
307 | void>::type> { |
308 | using type = CompressedObjectPtr; |
309 | }; |
310 | |
311 | #define DEFINE_COMPRESSED_POINTER(klass, base) \ |
312 | class Compressed##klass##Ptr : public Compressed##base##Ptr { \ |
313 | public: \ |
314 | explicit Compressed##klass##Ptr(klass##Ptr uncompressed) \ |
315 | : Compressed##base##Ptr(uncompressed) {} \ |
316 | const klass##Ptr& operator=(const klass##Ptr& other) { \ |
317 | compressed_pointer_ = static_cast<uint32_t>(static_cast<uword>(other)); \ |
318 | return other; \ |
319 | } \ |
320 | klass##Ptr Decompress(uword heap_base) const { \ |
321 | return klass##Ptr(CompressedObjectPtr::Decompress(heap_base)); \ |
322 | } \ |
323 | }; |
324 | #endif |
325 | |
326 | #define DEFINE_TAGGED_POINTER(klass, base) \ |
327 | class Untagged##klass; \ |
328 | class klass##Ptr : public base##Ptr { \ |
329 | public: \ |
330 | klass##Ptr* operator->() { \ |
331 | return this; \ |
332 | } \ |
333 | const klass##Ptr* operator->() const { \ |
334 | return this; \ |
335 | } \ |
336 | Untagged##klass* untag() { \ |
337 | return reinterpret_cast<Untagged##klass*>(untagged_pointer()); \ |
338 | } \ |
339 | /* TODO: Return const pointer */ \ |
340 | Untagged##klass* untag() const { \ |
341 | return reinterpret_cast<Untagged##klass*>(untagged_pointer()); \ |
342 | } \ |
343 | klass##Ptr& operator=(const klass##Ptr& other) = default; \ |
344 | constexpr klass##Ptr(const klass##Ptr& other) = default; \ |
345 | explicit constexpr klass##Ptr(const ObjectPtr& other) \ |
346 | : base##Ptr(other) {} \ |
347 | klass##Ptr() : base##Ptr() {} \ |
348 | explicit constexpr klass##Ptr(uword tagged) : base##Ptr(tagged) {} \ |
349 | explicit constexpr klass##Ptr(intptr_t tagged) : base##Ptr(tagged) {} \ |
350 | constexpr klass##Ptr(std::nullptr_t) : base##Ptr(nullptr) {} /* NOLINT */ \ |
351 | explicit klass##Ptr(const UntaggedObject* untagged) \ |
352 | : base##Ptr(reinterpret_cast<uword>(untagged) + kHeapObjectTag) {} \ |
353 | klass##Ptr Decompress(uword heap_base) const { \ |
354 | return *this; \ |
355 | } \ |
356 | }; \ |
357 | DEFINE_COMPRESSED_POINTER(klass, base) |
358 | |
359 | DEFINE_TAGGED_POINTER(Class, Object) |
360 | DEFINE_TAGGED_POINTER(PatchClass, Object) |
361 | DEFINE_TAGGED_POINTER(Function, Object) |
362 | DEFINE_TAGGED_POINTER(ClosureData, Object) |
363 | DEFINE_TAGGED_POINTER(FfiTrampolineData, Object) |
364 | DEFINE_TAGGED_POINTER(Field, Object) |
365 | DEFINE_TAGGED_POINTER(Script, Object) |
366 | DEFINE_TAGGED_POINTER(Library, Object) |
367 | DEFINE_TAGGED_POINTER(Namespace, Object) |
368 | DEFINE_TAGGED_POINTER(KernelProgramInfo, Object) |
369 | DEFINE_TAGGED_POINTER(WeakSerializationReference, Object) |
370 | DEFINE_TAGGED_POINTER(WeakArray, Object) |
371 | DEFINE_TAGGED_POINTER(Code, Object) |
372 | DEFINE_TAGGED_POINTER(ObjectPool, Object) |
373 | DEFINE_TAGGED_POINTER(Instructions, Object) |
374 | DEFINE_TAGGED_POINTER(InstructionsSection, Object) |
375 | DEFINE_TAGGED_POINTER(InstructionsTable, Object) |
376 | DEFINE_TAGGED_POINTER(PcDescriptors, Object) |
377 | DEFINE_TAGGED_POINTER(CodeSourceMap, Object) |
378 | DEFINE_TAGGED_POINTER(CompressedStackMaps, Object) |
379 | DEFINE_TAGGED_POINTER(LocalVarDescriptors, Object) |
380 | DEFINE_TAGGED_POINTER(ExceptionHandlers, Object) |
381 | DEFINE_TAGGED_POINTER(Context, Object) |
382 | DEFINE_TAGGED_POINTER(ContextScope, Object) |
383 | DEFINE_TAGGED_POINTER(Sentinel, Object) |
384 | DEFINE_TAGGED_POINTER(SingleTargetCache, Object) |
385 | DEFINE_TAGGED_POINTER(UnlinkedCall, Object) |
386 | DEFINE_TAGGED_POINTER(MonomorphicSmiableCall, Object) |
387 | DEFINE_TAGGED_POINTER(CallSiteData, Object) |
388 | DEFINE_TAGGED_POINTER(ICData, CallSiteData) |
389 | DEFINE_TAGGED_POINTER(MegamorphicCache, CallSiteData) |
390 | DEFINE_TAGGED_POINTER(SubtypeTestCache, Object) |
391 | DEFINE_TAGGED_POINTER(LoadingUnit, Object) |
392 | DEFINE_TAGGED_POINTER(Error, Object) |
393 | DEFINE_TAGGED_POINTER(ApiError, Error) |
394 | DEFINE_TAGGED_POINTER(LanguageError, Error) |
395 | DEFINE_TAGGED_POINTER(UnhandledException, Error) |
396 | DEFINE_TAGGED_POINTER(UnwindError, Error) |
397 | DEFINE_TAGGED_POINTER(Instance, Object) |
398 | DEFINE_TAGGED_POINTER(LibraryPrefix, Instance) |
399 | DEFINE_TAGGED_POINTER(TypeArguments, Instance) |
400 | DEFINE_TAGGED_POINTER(TypeParameters, Object) |
401 | DEFINE_TAGGED_POINTER(AbstractType, Instance) |
402 | DEFINE_TAGGED_POINTER(Type, AbstractType) |
403 | DEFINE_TAGGED_POINTER(FunctionType, AbstractType) |
404 | DEFINE_TAGGED_POINTER(RecordType, AbstractType) |
405 | DEFINE_TAGGED_POINTER(TypeParameter, AbstractType) |
406 | DEFINE_TAGGED_POINTER(Closure, Instance) |
407 | DEFINE_TAGGED_POINTER(Number, Instance) |
408 | DEFINE_TAGGED_POINTER(Integer, Number) |
409 | DEFINE_TAGGED_POINTER(Smi, Integer) |
410 | DEFINE_TAGGED_POINTER(Mint, Integer) |
411 | DEFINE_TAGGED_POINTER(Double, Number) |
412 | DEFINE_TAGGED_POINTER(String, Instance) |
413 | DEFINE_TAGGED_POINTER(OneByteString, String) |
414 | DEFINE_TAGGED_POINTER(TwoByteString, String) |
415 | DEFINE_TAGGED_POINTER(Record, Instance) |
416 | DEFINE_TAGGED_POINTER(PointerBase, Instance) |
417 | DEFINE_TAGGED_POINTER(TypedDataBase, PointerBase) |
418 | DEFINE_TAGGED_POINTER(TypedData, TypedDataBase) |
419 | DEFINE_TAGGED_POINTER(TypedDataView, TypedDataBase) |
420 | DEFINE_TAGGED_POINTER(ExternalOneByteString, String) |
421 | DEFINE_TAGGED_POINTER(ExternalTwoByteString, String) |
422 | DEFINE_TAGGED_POINTER(Bool, Instance) |
423 | DEFINE_TAGGED_POINTER(Array, Instance) |
424 | DEFINE_TAGGED_POINTER(ImmutableArray, Array) |
425 | DEFINE_TAGGED_POINTER(GrowableObjectArray, Instance) |
426 | DEFINE_TAGGED_POINTER(LinkedHashBase, Instance) |
427 | DEFINE_TAGGED_POINTER(Map, LinkedHashBase) |
428 | DEFINE_TAGGED_POINTER(Set, LinkedHashBase) |
429 | DEFINE_TAGGED_POINTER(ConstMap, Map) |
430 | DEFINE_TAGGED_POINTER(ConstSet, Set) |
431 | DEFINE_TAGGED_POINTER(Float32x4, Instance) |
432 | DEFINE_TAGGED_POINTER(Int32x4, Instance) |
433 | DEFINE_TAGGED_POINTER(Float64x2, Instance) |
434 | DEFINE_TAGGED_POINTER(ExternalTypedData, TypedDataBase) |
435 | DEFINE_TAGGED_POINTER(Pointer, PointerBase) |
436 | DEFINE_TAGGED_POINTER(DynamicLibrary, Instance) |
437 | DEFINE_TAGGED_POINTER(Capability, Instance) |
438 | DEFINE_TAGGED_POINTER(SendPort, Instance) |
439 | DEFINE_TAGGED_POINTER(ReceivePort, Instance) |
440 | DEFINE_TAGGED_POINTER(TransferableTypedData, Instance) |
441 | DEFINE_TAGGED_POINTER(StackTrace, Instance) |
442 | DEFINE_TAGGED_POINTER(SuspendState, Instance) |
443 | DEFINE_TAGGED_POINTER(RegExp, Instance) |
444 | DEFINE_TAGGED_POINTER(WeakProperty, Instance) |
445 | DEFINE_TAGGED_POINTER(WeakReference, Instance) |
446 | DEFINE_TAGGED_POINTER(FinalizerBase, Instance) |
447 | DEFINE_TAGGED_POINTER(Finalizer, Instance) |
448 | DEFINE_TAGGED_POINTER(FinalizerEntry, Instance) |
449 | DEFINE_TAGGED_POINTER(NativeFinalizer, Instance) |
450 | DEFINE_TAGGED_POINTER(MirrorReference, Instance) |
451 | DEFINE_TAGGED_POINTER(UserTag, Instance) |
452 | DEFINE_TAGGED_POINTER(FutureOr, Instance) |
453 | #undef DEFINE_TAGGED_POINTER |
454 | |
455 | inline intptr_t RawSmiValue(const SmiPtr raw_value) { |
456 | #if !defined(DART_COMPRESSED_POINTERS) |
457 | const intptr_t value = static_cast<intptr_t>(raw_value); |
458 | #else |
459 | const intptr_t value = static_cast<intptr_t>(static_cast<int32_t>( |
460 | static_cast<uint32_t>(static_cast<uintptr_t>(raw_value)))); |
461 | #endif |
462 | ASSERT((value & kSmiTagMask) == kSmiTag); |
463 | return (value >> kSmiTagShift); |
464 | } |
465 | |
466 | } // namespace dart |
467 | |
468 | #endif // RUNTIME_VM_TAGGED_POINTER_H_ |
469 |
Definitions
- IsWellFormed
- IsImmediateObject
- IsHeapObject
- IsNewObject
- IsNewObjectMayBeSmi
- IsOldObject
- IsImmediateOrOldObject
- IsImmediateOrNewObject
- ObjectPtr
- untag
- IsStringInstance
- IsRawNull
- IsDartInstance
- IsFreeListElement
- IsForwardingCorpse
- IsPseudoObject
- GetClassIdMayBeSmi
- operator==
- operator!=
- operator==
- operator!=
- operator bool
- operator long
- operator long long
- operator unsigned long
- operator unsigned long long
- operator=
- ObjectPtr
- ObjectPtr
- ObjectPtr
- ObjectPtr
- ObjectPtr
- ObjectPtr
- Decompress
- DecompressSmi
- heap_base
- untagged_pointer
- operator<<
- is_uncompressed_ptr
- is_compressed_ptr
- base_ptr_type
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- untag
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
- Decompress
Learn more about Flutter for embedded and desktop on industrialflutter.com