blob: 10378e8bc904d4b849726435a3257e079bb21da9 [file] [log] [blame]
Mathieu Chartier3f7f03c2016-09-26 11:39:52 -07001/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef ART_RUNTIME_MIRROR_OBJ_PTR_H_
18#define ART_RUNTIME_MIRROR_OBJ_PTR_H_
19
20#include "base/mutex.h" // For Locks::mutator_lock_.
21#include "globals.h"
22#include "mirror/object_reference.h"
23#include "utils.h"
24
25namespace art {
26namespace mirror {
27
28class Object;
29
30// Value type representing a pointer to a mirror::Object of type MirrorType
31// Pass kPoison as a template boolean for testing in non-debug builds.
32// Note that the functions are not 100% thread safe and may have spurious positive check passes in
33// these cases.
34template<class MirrorType, bool kPoison = kIsDebugBuild>
35class ObjPtr {
36 static constexpr size_t kCookieShift =
37 sizeof(mirror::HeapReference<mirror::Object>) * kBitsPerByte - kObjectAlignmentShift;
38 static constexpr size_t kCookieBits = sizeof(uintptr_t) * kBitsPerByte - kCookieShift;
39 static constexpr uintptr_t kCookieMask = (static_cast<uintptr_t>(1u) << kCookieBits) - 1;
40
41 static_assert(kCookieBits >= kObjectAlignmentShift,
42 "must have a least kObjectAlignmentShift bits");
43
44 public:
45 ALWAYS_INLINE ObjPtr() REQUIRES_SHARED(Locks::mutator_lock_) : reference_(0u) {}
46
47 ALWAYS_INLINE explicit ObjPtr(MirrorType* ptr) REQUIRES_SHARED(Locks::mutator_lock_)
48 : reference_(Encode(ptr)) {}
49
50 ALWAYS_INLINE explicit ObjPtr(const ObjPtr& other) REQUIRES_SHARED(Locks::mutator_lock_)
51 = default;
52
53 ALWAYS_INLINE ObjPtr& operator=(const ObjPtr& other) {
54 reference_ = other.reference_;
55 return *this;
56 }
57
58 ALWAYS_INLINE ObjPtr& operator=(MirrorType* ptr) REQUIRES_SHARED(Locks::mutator_lock_) {
59 Assign(ptr);
60 return *this;
61 }
62
63 ALWAYS_INLINE void Assign(MirrorType* ptr) REQUIRES_SHARED(Locks::mutator_lock_) {
64 reference_ = Encode(ptr);
65 }
66
67 ALWAYS_INLINE MirrorType* operator->() const REQUIRES_SHARED(Locks::mutator_lock_) {
68 return Get();
69 }
70
71 ALWAYS_INLINE MirrorType* Get() const REQUIRES_SHARED(Locks::mutator_lock_) {
72 return Decode();
73 }
74
75 ALWAYS_INLINE bool IsNull() const {
76 return reference_ == 0;
77 }
78
79 ALWAYS_INLINE bool IsValid() const REQUIRES_SHARED(Locks::mutator_lock_) {
80 if (!kPoison || IsNull()) {
81 return true;
82 }
83 return GetCookie() == TrimCookie(Thread::Current()->GetPoisonObjectCookie());
84 }
85
86 ALWAYS_INLINE void AssertValid() const REQUIRES_SHARED(Locks::mutator_lock_) {
87 if (kPoison) {
88 CHECK(IsValid()) << "Stale object pointer, expected cookie "
89 << TrimCookie(Thread::Current()->GetPoisonObjectCookie()) << " but got " << GetCookie();
90 }
91 }
92
93 ALWAYS_INLINE bool operator==(const ObjPtr& ptr) const REQUIRES_SHARED(Locks::mutator_lock_) {
94 return Decode() == ptr.Decode();
95 }
96
97 ALWAYS_INLINE bool operator==(const MirrorType* ptr) const REQUIRES_SHARED(Locks::mutator_lock_) {
98 return Decode() == ptr;
99 }
100
101 ALWAYS_INLINE bool operator==(std::nullptr_t) const REQUIRES_SHARED(Locks::mutator_lock_) {
102 return IsNull();
103 }
104
105 ALWAYS_INLINE bool operator!=(const ObjPtr& ptr) const REQUIRES_SHARED(Locks::mutator_lock_) {
106 return Decode() != ptr.Decode();
107 }
108
109 ALWAYS_INLINE bool operator!=(const MirrorType* ptr) const REQUIRES_SHARED(Locks::mutator_lock_) {
110 return Decode() != ptr;
111 }
112
113 ALWAYS_INLINE bool operator!=(std::nullptr_t) const REQUIRES_SHARED(Locks::mutator_lock_) {
114 return !IsNull();
115 }
116
117 private:
118 // Trim off high bits of thread local cookie.
119 ALWAYS_INLINE static uintptr_t TrimCookie(uintptr_t cookie) {
120 return cookie & kCookieMask;
121 }
122
123 ALWAYS_INLINE uintptr_t GetCookie() const {
124 return reference_ >> kCookieShift;
125 }
126
127 ALWAYS_INLINE static uintptr_t Encode(MirrorType* ptr) REQUIRES_SHARED(Locks::mutator_lock_) {
128 uintptr_t ref = reinterpret_cast<uintptr_t>(ptr);
129 if (kPoison && ref != 0) {
130 DCHECK_LE(ref, 0xFFFFFFFFU);
131 ref >>= kObjectAlignmentShift;
132 // Put cookie in high bits.
133 Thread* self = Thread::Current();
134 DCHECK(self != nullptr);
135 ref |= self->GetPoisonObjectCookie() << kCookieShift;
136 }
137 return ref;
138 }
139
140 // Decode makes sure that the object pointer is valid.
141 ALWAYS_INLINE MirrorType* Decode() const REQUIRES_SHARED(Locks::mutator_lock_) {
142 AssertValid();
143 if (kPoison) {
144 return reinterpret_cast<MirrorType*>(
145 static_cast<uintptr_t>(static_cast<uint32_t>(reference_ << kObjectAlignmentShift)));
146 } else {
147 return reinterpret_cast<MirrorType*>(reference_);
148 }
149 }
150
151 // The encoded reference and cookie.
152 uintptr_t reference_;
153};
154
155
156} // namespace mirror
157} // namespace art
158
159#endif // ART_RUNTIME_MIRROR_OBJ_PTR_H_