mirror of
https://github.com/dart-lang/sdk
synced 2024-09-19 21:01:50 +00:00
c0f6b37d17
----- Adds a few type traits for operating on (Compressed)ObjectPtr types: * is_compressed_ptr<T>::value is true for compressed pointer types and false for uncompressed pointer types. * is_uncompressed_ptr<T>::value is false for compressed pointer types and true for uncompressed pointer types. * base_ptr_type<T>::type is ObjectPtr for uncompressed pointer types and CompressedObjectPtr for compressed pointer types. Note: If DART_COMPRESSED_POINTERS is not enabled, all pointers are uncompressed and the above traits function accordingly. That means that is_compressed_ptr<T>::value is always false, is_uncompressed_ptr<T>::value is true for all object pointers, and base_ptr_type<T>::type is ObjectPtr for all object pointers, even if they contain Compressed in the name. ----- The following changes have been made to the VISIT_* macros: * VISIT_NOTHING: no change. * VISIT_FROM: takes only a field name now, and retrieves the type of the field to determine which base pointer type to use for from(). Note that VISIT_FROM must now come _after_ the declaration of the field, since it retrieves the type from the declaration. * VISIT_TO: takes only a field name now, and retrieves the type of the field to determine which base pointer type to use for to(). * (removed) VISIT_TO_LENGTH: Instead, VISIT_TO creates a to() method that takes an optional length argument (defaults to 0). * (new) VISIT_FROM_PAYLOAD_START: takes the object pointer type of the payload elements and creates a from() that returns the beginning element of the payload. Note that a payload element must be a single object ptr to use this macro. * (new) VISIT_TO_PAYLOAD_END: takes the object pointer type of the payload elements and creates a to() which takes a non-optional length argument and returns the last element of the payload. Note that a payload element must be a single object ptr to use this macro. If one of the {COMPRESSED_,}VARIABLE_POINTER_FIELDS macros are used, then VISIT_TO_PAYLOAD_END should not be, as those macros already include a use of it. ----- In addition, each Untagged<Class> class now has a static constexpr bool field kContainsCompressedPointers. This field is false for UntaggedObject, and for other Untagged<Class> classes, it is either inherited from the parent class or set during VISIT_FROM and the new VISIT_FROM_PAYLOAD_START macro. VISIT_TO and the new VISIT_TO_PAYLOAD_END macro double-check at compile time that the type retrieved or provided is a compressed type if kContainsCompressedPointers is true, and uncompressed if false. If the elements of a payload are not object pointers, but rather a composite object that contains object pointers, then VISIT_FROM_PAYLOAD_START/VISIT_TO_PAYLOAD_END cannot be used. Instead, use DEFINE_COMPRESSED_POINTERS(type), where type is the type of one of the object pointers in the composite object, to appropriately define kContainsCompressedPointers. Note that this field will always be false when DART_COMPRESSED_POINTERS is not defined. ----- For classes, a static constexpr ContainsCompressedPointers() predicate is created, based on the associated untagged class's field. For instances of Class, there is an instance predicate Class::HasCompressedPointers() that returns whether instances of a given class object contain compressed pointers. Change all calls to InitializeObject and Object::Allocate to pass in the result of the appropriate predicate. TEST=Refactoring, so current tests on CI, especially on x64c trybots. Cq-Include-Trybots: luci.dart.try:vm-kernel-linux-debug-x64c-try,vm-kernel-precomp-linux-debug-x64c-try,vm-kernel-precomp-linux-debug-x64-try,vm-kernel-linux-debug-x64-try Change-Id: Ifb61f72885bd8b951167becbccf8ec3337a922b1 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/196931 Reviewed-by: Liam Appelbe <liama@google.com> Reviewed-by: Ryan Macnak <rmacnak@google.com> Commit-Queue: Tess Strickland <sstrickl@google.com>
416 lines
16 KiB
C++
416 lines
16 KiB
C++
// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
|
|
// for details. All rights reserved. Use of this source code is governed by a
|
|
// BSD-style license that can be found in the LICENSE file.
|
|
|
|
#ifndef RUNTIME_VM_TAGGED_POINTER_H_
|
|
#define RUNTIME_VM_TAGGED_POINTER_H_
|
|
|
|
#include <type_traits>
|
|
#include "platform/assert.h"
|
|
#include "platform/utils.h"
|
|
#include "vm/class_id.h"
|
|
#include "vm/pointer_tagging.h"
|
|
|
|
namespace dart {
|
|
|
|
class IsolateGroup;
|
|
class UntaggedObject;
|
|
|
|
class ObjectPtr {
|
|
public:
|
|
ObjectPtr* operator->() { return this; }
|
|
const ObjectPtr* operator->() const { return this; }
|
|
UntaggedObject* untag() const {
|
|
return reinterpret_cast<UntaggedObject*>(untagged_pointer());
|
|
}
|
|
|
|
bool IsWellFormed() const {
|
|
uword value = tagged_pointer_;
|
|
return (value & kSmiTagMask) == 0 ||
|
|
Utils::IsAligned(value - kHeapObjectTag, kWordSize);
|
|
}
|
|
bool IsHeapObject() const {
|
|
ASSERT(IsWellFormed());
|
|
uword value = tagged_pointer_;
|
|
return (value & kSmiTagMask) == kHeapObjectTag;
|
|
}
|
|
// Assumes this is a heap object.
|
|
bool IsNewObject() const {
|
|
ASSERT(IsHeapObject());
|
|
uword addr = tagged_pointer_;
|
|
return (addr & kNewObjectAlignmentOffset) == kNewObjectAlignmentOffset;
|
|
}
|
|
bool IsNewObjectMayBeSmi() const {
|
|
static const uword kNewObjectBits =
|
|
(kNewObjectAlignmentOffset | kHeapObjectTag);
|
|
const uword addr = tagged_pointer_;
|
|
return (addr & kObjectAlignmentMask) == kNewObjectBits;
|
|
}
|
|
// Assumes this is a heap object.
|
|
bool IsOldObject() const {
|
|
ASSERT(IsHeapObject());
|
|
uword addr = tagged_pointer_;
|
|
return (addr & kNewObjectAlignmentOffset) == kOldObjectAlignmentOffset;
|
|
}
|
|
|
|
// Like !IsHeapObject() || IsOldObject(), but compiles to a single branch.
|
|
bool IsSmiOrOldObject() const {
|
|
ASSERT(IsWellFormed());
|
|
static const uword kNewObjectBits =
|
|
(kNewObjectAlignmentOffset | kHeapObjectTag);
|
|
const uword addr = tagged_pointer_;
|
|
return (addr & kObjectAlignmentMask) != kNewObjectBits;
|
|
}
|
|
|
|
// Like !IsHeapObject() || IsNewObject(), but compiles to a single branch.
|
|
bool IsSmiOrNewObject() const {
|
|
ASSERT(IsWellFormed());
|
|
static const uword kOldObjectBits =
|
|
(kOldObjectAlignmentOffset | kHeapObjectTag);
|
|
const uword addr = tagged_pointer_;
|
|
return (addr & kObjectAlignmentMask) != kOldObjectBits;
|
|
}
|
|
|
|
#define DEFINE_IS_CID(clazz) \
|
|
bool Is##clazz() const { return ((GetClassId() == k##clazz##Cid)); }
|
|
CLASS_LIST(DEFINE_IS_CID)
|
|
#undef DEFINE_IS_CID
|
|
|
|
#define DEFINE_IS_CID(clazz) \
|
|
bool IsTypedData##clazz() const { \
|
|
return ((GetClassId() == kTypedData##clazz##Cid)); \
|
|
} \
|
|
bool IsTypedDataView##clazz() const { \
|
|
return ((GetClassId() == kTypedData##clazz##ViewCid)); \
|
|
} \
|
|
bool IsExternalTypedData##clazz() const { \
|
|
return ((GetClassId() == kExternalTypedData##clazz##Cid)); \
|
|
}
|
|
CLASS_LIST_TYPED_DATA(DEFINE_IS_CID)
|
|
#undef DEFINE_IS_CID
|
|
|
|
#define DEFINE_IS_CID(clazz) \
|
|
bool IsFfi##clazz() const { return ((GetClassId() == kFfi##clazz##Cid)); }
|
|
CLASS_LIST_FFI(DEFINE_IS_CID)
|
|
#undef DEFINE_IS_CID
|
|
|
|
bool IsStringInstance() const { return IsStringClassId(GetClassId()); }
|
|
bool IsRawNull() const { return GetClassId() == kNullCid; }
|
|
bool IsDartInstance() const {
|
|
return (!IsHeapObject() || (GetClassId() >= kInstanceCid));
|
|
}
|
|
bool IsFreeListElement() const {
|
|
return ((GetClassId() == kFreeListElement));
|
|
}
|
|
bool IsForwardingCorpse() const {
|
|
return ((GetClassId() == kForwardingCorpse));
|
|
}
|
|
bool IsPseudoObject() const {
|
|
return IsFreeListElement() || IsForwardingCorpse();
|
|
}
|
|
|
|
intptr_t GetClassId() const;
|
|
intptr_t GetClassIdMayBeSmi() const {
|
|
return IsHeapObject() ? GetClassId() : static_cast<intptr_t>(kSmiCid);
|
|
}
|
|
|
|
void Validate(IsolateGroup* isolate_group) const;
|
|
|
|
bool operator==(const ObjectPtr& other) {
|
|
return tagged_pointer_ == other.tagged_pointer_;
|
|
}
|
|
bool operator!=(const ObjectPtr& other) {
|
|
return tagged_pointer_ != other.tagged_pointer_;
|
|
}
|
|
constexpr bool operator==(const ObjectPtr& other) const {
|
|
return tagged_pointer_ == other.tagged_pointer_;
|
|
}
|
|
constexpr bool operator!=(const ObjectPtr& other) const {
|
|
return tagged_pointer_ != other.tagged_pointer_;
|
|
}
|
|
bool operator==(const std::nullptr_t& other) { return tagged_pointer_ == 0; }
|
|
bool operator!=(const std::nullptr_t& other) { return tagged_pointer_ != 0; }
|
|
constexpr bool operator==(const std::nullptr_t& other) const {
|
|
return tagged_pointer_ == 0;
|
|
}
|
|
constexpr bool operator!=(const std::nullptr_t& other) const {
|
|
return tagged_pointer_ != 0;
|
|
}
|
|
|
|
// Use explicit null comparisons instead.
|
|
operator bool() const = delete;
|
|
|
|
// The underlying types of int32_t/int64_t and intptr_t are sometimes
|
|
// different and sometimes the same, depending on the platform. With
|
|
// only a conversion operator for intptr_t, on 64-bit Mac a static_cast
|
|
// to int64_t fails because it tries conversion to bool (!) rather than
|
|
// intptr_t. So we exhaustive define all the valid conversions based on
|
|
// the underlying types.
|
|
#if INT_MAX == INTPTR_MAX
|
|
explicit operator int() const { // NOLINT
|
|
return static_cast<int>(tagged_pointer_); // NOLINT
|
|
}
|
|
#endif
|
|
#if LONG_MAX == INTPTR_MAX
|
|
explicit operator long() const { // NOLINT
|
|
return static_cast<long>(tagged_pointer_); // NOLINT
|
|
}
|
|
#endif
|
|
#if LLONG_MAX == INTPTR_MAX
|
|
explicit operator long long() const { // NOLINT
|
|
return static_cast<long long>(tagged_pointer_); // NOLINT
|
|
}
|
|
#endif
|
|
#if UINT_MAX == UINTPTR_MAX
|
|
explicit operator unsigned int() const { // NOLINT
|
|
return static_cast<unsigned int>(tagged_pointer_); // NOLINT
|
|
}
|
|
#endif
|
|
#if ULONG_MAX == UINTPTR_MAX
|
|
explicit operator unsigned long() const { // NOLINT
|
|
return static_cast<unsigned long>(tagged_pointer_); // NOLINT
|
|
}
|
|
#endif
|
|
#if ULLONG_MAX == UINTPTR_MAX
|
|
explicit operator unsigned long long() const { // NOLINT
|
|
return static_cast<unsigned long long>(tagged_pointer_); // NOLINT
|
|
}
|
|
#endif
|
|
|
|
// Must be trivially copyable for std::atomic.
|
|
ObjectPtr& operator=(const ObjectPtr& other) = default;
|
|
constexpr ObjectPtr(const ObjectPtr& other) = default;
|
|
|
|
ObjectPtr() : tagged_pointer_(0) {}
|
|
explicit constexpr ObjectPtr(uword tagged) : tagged_pointer_(tagged) {}
|
|
explicit constexpr ObjectPtr(intptr_t tagged) : tagged_pointer_(tagged) {}
|
|
constexpr ObjectPtr(std::nullptr_t) : tagged_pointer_(0) {} // NOLINT
|
|
explicit ObjectPtr(UntaggedObject* heap_object)
|
|
: tagged_pointer_(reinterpret_cast<uword>(heap_object) + kHeapObjectTag) {
|
|
}
|
|
|
|
ObjectPtr Decompress(uword heap_base) const { return *this; }
|
|
ObjectPtr DecompressSmi() const { return *this; }
|
|
uword heap_base() const {
|
|
// TODO(rmacnak): Why does Windows have trouble linking GetClassId used
|
|
// here?
|
|
#if !defined(HOST_OS_WINDOWS)
|
|
ASSERT(IsHeapObject());
|
|
ASSERT(!IsInstructions());
|
|
ASSERT(!IsInstructionsSection());
|
|
#endif
|
|
return tagged_pointer_ & kHeapBaseMask;
|
|
}
|
|
|
|
protected:
|
|
uword untagged_pointer() const {
|
|
ASSERT(IsHeapObject());
|
|
return tagged_pointer_ - kHeapObjectTag;
|
|
}
|
|
|
|
uword tagged_pointer_;
|
|
};
|
|
|
|
// Needed by the printing in the EXPECT macros.
|
|
#if defined(DEBUG) || defined(TESTING)
|
|
inline std::ostream& operator<<(std::ostream& os, const ObjectPtr& obj) {
|
|
os << reinterpret_cast<void*>(static_cast<uword>(obj));
|
|
return os;
|
|
}
|
|
#endif
|
|
|
|
template <typename T, typename Enable = void>
|
|
struct is_uncompressed_ptr : std::false_type {};
|
|
template <typename T>
|
|
struct is_uncompressed_ptr<
|
|
T,
|
|
typename std::enable_if<std::is_base_of<ObjectPtr, T>::value, void>::type>
|
|
: std::true_type {};
|
|
template <typename T, typename Enable = void>
|
|
struct is_compressed_ptr : std::false_type {};
|
|
|
|
template <typename T, typename Enable = void>
|
|
struct base_ptr_type {
|
|
using type =
|
|
typename std::enable_if<is_uncompressed_ptr<T>::value, ObjectPtr>::type;
|
|
};
|
|
|
|
#if !defined(DART_COMPRESSED_POINTERS)
|
|
typedef ObjectPtr CompressedObjectPtr;
|
|
#define DEFINE_COMPRESSED_POINTER(klass, base) \
|
|
typedef klass##Ptr Compressed##klass##Ptr;
|
|
#else
|
|
class CompressedObjectPtr {
|
|
public:
|
|
explicit CompressedObjectPtr(ObjectPtr uncompressed)
|
|
: compressed_pointer_(
|
|
static_cast<uint32_t>(static_cast<uword>(uncompressed))) {}
|
|
|
|
ObjectPtr Decompress(uword heap_base) const {
|
|
return static_cast<ObjectPtr>(static_cast<uword>(compressed_pointer_) +
|
|
heap_base);
|
|
}
|
|
|
|
ObjectPtr DecompressSmi() const {
|
|
ASSERT((compressed_pointer_ & kSmiTagMask) != kHeapObjectTag);
|
|
return static_cast<ObjectPtr>(static_cast<uword>(compressed_pointer_));
|
|
}
|
|
|
|
const ObjectPtr& operator=(const ObjectPtr& other) {
|
|
compressed_pointer_ = static_cast<uint32_t>(static_cast<uword>(other));
|
|
return other;
|
|
}
|
|
|
|
protected:
|
|
uint32_t compressed_pointer_;
|
|
};
|
|
|
|
template <typename T>
|
|
struct is_compressed_ptr<
|
|
T,
|
|
typename std::enable_if<std::is_base_of<CompressedObjectPtr, T>::value,
|
|
void>::type> : std::true_type {};
|
|
template <typename T>
|
|
struct base_ptr_type<
|
|
T,
|
|
typename std::enable_if<std::is_base_of<CompressedObjectPtr, T>::value,
|
|
void>::type> {
|
|
using type = CompressedObjectPtr;
|
|
};
|
|
|
|
#define DEFINE_COMPRESSED_POINTER(klass, base) \
|
|
class Compressed##klass##Ptr : public Compressed##base##Ptr { \
|
|
public: \
|
|
explicit Compressed##klass##Ptr(klass##Ptr uncompressed) \
|
|
: Compressed##base##Ptr(uncompressed) {} \
|
|
const klass##Ptr& operator=(const klass##Ptr& other) { \
|
|
compressed_pointer_ = static_cast<uint32_t>(static_cast<uword>(other)); \
|
|
return other; \
|
|
} \
|
|
};
|
|
#endif
|
|
|
|
#define DEFINE_TAGGED_POINTER(klass, base) \
|
|
class Untagged##klass; \
|
|
class klass##Ptr : public base##Ptr { \
|
|
public: \
|
|
klass##Ptr* operator->() { return this; } \
|
|
const klass##Ptr* operator->() const { return this; } \
|
|
Untagged##klass* untag() { \
|
|
return reinterpret_cast<Untagged##klass*>(untagged_pointer()); \
|
|
} \
|
|
/* TODO: Return const pointer */ \
|
|
Untagged##klass* untag() const { \
|
|
return reinterpret_cast<Untagged##klass*>(untagged_pointer()); \
|
|
} \
|
|
klass##Ptr& operator=(const klass##Ptr& other) = default; \
|
|
constexpr klass##Ptr(const klass##Ptr& other) = default; \
|
|
explicit constexpr klass##Ptr(const ObjectPtr& other) \
|
|
: base##Ptr(other) {} \
|
|
klass##Ptr() : base##Ptr() {} \
|
|
explicit constexpr klass##Ptr(uword tagged) : base##Ptr(tagged) {} \
|
|
explicit constexpr klass##Ptr(intptr_t tagged) : base##Ptr(tagged) {} \
|
|
constexpr klass##Ptr(std::nullptr_t) : base##Ptr(nullptr) {} /* NOLINT */ \
|
|
explicit klass##Ptr(const UntaggedObject* untagged) \
|
|
: base##Ptr(reinterpret_cast<uword>(untagged) + kHeapObjectTag) {} \
|
|
}; \
|
|
DEFINE_COMPRESSED_POINTER(klass, base)
|
|
|
|
DEFINE_TAGGED_POINTER(Class, Object)
|
|
DEFINE_TAGGED_POINTER(PatchClass, Object)
|
|
DEFINE_TAGGED_POINTER(Function, Object)
|
|
DEFINE_TAGGED_POINTER(ClosureData, Object)
|
|
DEFINE_TAGGED_POINTER(FfiTrampolineData, Object)
|
|
DEFINE_TAGGED_POINTER(Field, Object)
|
|
DEFINE_TAGGED_POINTER(Script, Object)
|
|
DEFINE_TAGGED_POINTER(Library, Object)
|
|
DEFINE_TAGGED_POINTER(Namespace, Object)
|
|
DEFINE_TAGGED_POINTER(KernelProgramInfo, Object)
|
|
DEFINE_TAGGED_POINTER(WeakSerializationReference, Object)
|
|
DEFINE_TAGGED_POINTER(Code, Object)
|
|
DEFINE_TAGGED_POINTER(ObjectPool, Object)
|
|
DEFINE_TAGGED_POINTER(Instructions, Object)
|
|
DEFINE_TAGGED_POINTER(InstructionsSection, Object)
|
|
DEFINE_TAGGED_POINTER(InstructionsTable, Object)
|
|
DEFINE_TAGGED_POINTER(PcDescriptors, Object)
|
|
DEFINE_TAGGED_POINTER(CodeSourceMap, Object)
|
|
DEFINE_TAGGED_POINTER(CompressedStackMaps, Object)
|
|
DEFINE_TAGGED_POINTER(LocalVarDescriptors, Object)
|
|
DEFINE_TAGGED_POINTER(ExceptionHandlers, Object)
|
|
DEFINE_TAGGED_POINTER(Context, Object)
|
|
DEFINE_TAGGED_POINTER(ContextScope, Object)
|
|
DEFINE_TAGGED_POINTER(SingleTargetCache, Object)
|
|
DEFINE_TAGGED_POINTER(UnlinkedCall, Object)
|
|
DEFINE_TAGGED_POINTER(MonomorphicSmiableCall, Object)
|
|
DEFINE_TAGGED_POINTER(CallSiteData, Object)
|
|
DEFINE_TAGGED_POINTER(ICData, CallSiteData)
|
|
DEFINE_TAGGED_POINTER(MegamorphicCache, CallSiteData)
|
|
DEFINE_TAGGED_POINTER(SubtypeTestCache, Object)
|
|
DEFINE_TAGGED_POINTER(LoadingUnit, Object)
|
|
DEFINE_TAGGED_POINTER(Error, Object)
|
|
DEFINE_TAGGED_POINTER(ApiError, Error)
|
|
DEFINE_TAGGED_POINTER(LanguageError, Error)
|
|
DEFINE_TAGGED_POINTER(UnhandledException, Error)
|
|
DEFINE_TAGGED_POINTER(UnwindError, Error)
|
|
DEFINE_TAGGED_POINTER(Instance, Object)
|
|
DEFINE_TAGGED_POINTER(LibraryPrefix, Instance)
|
|
DEFINE_TAGGED_POINTER(TypeArguments, Instance)
|
|
DEFINE_TAGGED_POINTER(TypeParameters, Object)
|
|
DEFINE_TAGGED_POINTER(AbstractType, Instance)
|
|
DEFINE_TAGGED_POINTER(Type, AbstractType)
|
|
DEFINE_TAGGED_POINTER(FunctionType, AbstractType)
|
|
DEFINE_TAGGED_POINTER(TypeRef, AbstractType)
|
|
DEFINE_TAGGED_POINTER(TypeParameter, AbstractType)
|
|
DEFINE_TAGGED_POINTER(Closure, Instance)
|
|
DEFINE_TAGGED_POINTER(Number, Instance)
|
|
DEFINE_TAGGED_POINTER(Integer, Number)
|
|
DEFINE_TAGGED_POINTER(Smi, Integer)
|
|
DEFINE_TAGGED_POINTER(Mint, Integer)
|
|
DEFINE_TAGGED_POINTER(Double, Number)
|
|
DEFINE_TAGGED_POINTER(String, Instance)
|
|
DEFINE_TAGGED_POINTER(OneByteString, String)
|
|
DEFINE_TAGGED_POINTER(TwoByteString, String)
|
|
DEFINE_TAGGED_POINTER(PointerBase, Instance)
|
|
DEFINE_TAGGED_POINTER(TypedDataBase, PointerBase)
|
|
DEFINE_TAGGED_POINTER(TypedData, TypedDataBase)
|
|
DEFINE_TAGGED_POINTER(TypedDataView, TypedDataBase)
|
|
DEFINE_TAGGED_POINTER(ExternalOneByteString, String)
|
|
DEFINE_TAGGED_POINTER(ExternalTwoByteString, String)
|
|
DEFINE_TAGGED_POINTER(Bool, Instance)
|
|
DEFINE_TAGGED_POINTER(Array, Instance)
|
|
DEFINE_TAGGED_POINTER(ImmutableArray, Array)
|
|
DEFINE_TAGGED_POINTER(GrowableObjectArray, Instance)
|
|
DEFINE_TAGGED_POINTER(LinkedHashMap, Instance)
|
|
DEFINE_TAGGED_POINTER(Float32x4, Instance)
|
|
DEFINE_TAGGED_POINTER(Int32x4, Instance)
|
|
DEFINE_TAGGED_POINTER(Float64x2, Instance)
|
|
DEFINE_TAGGED_POINTER(ExternalTypedData, TypedDataBase)
|
|
DEFINE_TAGGED_POINTER(Pointer, PointerBase)
|
|
DEFINE_TAGGED_POINTER(DynamicLibrary, Instance)
|
|
DEFINE_TAGGED_POINTER(Capability, Instance)
|
|
DEFINE_TAGGED_POINTER(SendPort, Instance)
|
|
DEFINE_TAGGED_POINTER(ReceivePort, Instance)
|
|
DEFINE_TAGGED_POINTER(TransferableTypedData, Instance)
|
|
DEFINE_TAGGED_POINTER(StackTrace, Instance)
|
|
DEFINE_TAGGED_POINTER(RegExp, Instance)
|
|
DEFINE_TAGGED_POINTER(WeakProperty, Instance)
|
|
DEFINE_TAGGED_POINTER(MirrorReference, Instance)
|
|
DEFINE_TAGGED_POINTER(UserTag, Instance)
|
|
DEFINE_TAGGED_POINTER(FutureOr, Instance)
|
|
#undef DEFINE_TAGGED_POINTER
|
|
|
|
inline intptr_t RawSmiValue(const SmiPtr raw_value) {
|
|
#if !defined(DART_COMPRESSED_POINTERS)
|
|
const intptr_t value = static_cast<intptr_t>(raw_value);
|
|
#else
|
|
const intptr_t value = static_cast<intptr_t>(static_cast<int32_t>(
|
|
static_cast<uint32_t>(static_cast<uintptr_t>(raw_value))));
|
|
#endif
|
|
ASSERT((value & kSmiTagMask) == kSmiTag);
|
|
return (value >> kSmiTagShift);
|
|
}
|
|
|
|
} // namespace dart
|
|
|
|
#endif // RUNTIME_VM_TAGGED_POINTER_H_
|