1/*
2 * Copyright (C) 2014 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_OBJECT_REFERENCE_H_
18#define ART_RUNTIME_MIRROR_OBJECT_REFERENCE_H_
19
20#include "base/atomic.h"
21#include "base/mutex.h"  // For Locks::mutator_lock_.
22#include "globals.h"
23#include "heap_poisoning.h"
24#include "obj_ptr.h"
25
26namespace art {
27namespace mirror {
28
29class Object;
30
31// Classes shared with the managed side of the world need to be packed so that they don't have
32// extra platform specific padding.
33#define MANAGED PACKED(4)
34
35template<bool kPoisonReferences, class MirrorType>
36class PtrCompression {
37 public:
38  // Compress reference to its bit representation.
39  static uint32_t Compress(MirrorType* mirror_ptr) {
40    uintptr_t as_bits = reinterpret_cast<uintptr_t>(mirror_ptr);
41    return static_cast<uint32_t>(kPoisonReferences ? -as_bits : as_bits);
42  }
43
44  // Uncompress an encoded reference from its bit representation.
45  static MirrorType* Decompress(uint32_t ref) {
46    uintptr_t as_bits = kPoisonReferences ? -ref : ref;
47    return reinterpret_cast<MirrorType*>(as_bits);
48  }
49
50  // Convert an ObjPtr to a compressed reference.
51  static uint32_t Compress(ObjPtr<MirrorType> ptr) REQUIRES_SHARED(Locks::mutator_lock_) {
52    return Compress(ptr.Ptr());
53  }
54};
55
56// Value type representing a reference to a mirror::Object of type MirrorType.
57template<bool kPoisonReferences, class MirrorType>
58class MANAGED ObjectReference {
59 private:
60  using Compression = PtrCompression<kPoisonReferences, MirrorType>;
61
62 public:
63  MirrorType* AsMirrorPtr() const {
64    return Compression::Decompress(reference_);
65  }
66
67  void Assign(MirrorType* other) {
68    reference_ = Compression::Compress(other);
69  }
70
71  void Assign(ObjPtr<MirrorType> ptr) REQUIRES_SHARED(Locks::mutator_lock_);
72
73  void Clear() {
74    reference_ = 0;
75    DCHECK(IsNull());
76  }
77
78  bool IsNull() const {
79    return reference_ == 0;
80  }
81
82  uint32_t AsVRegValue() const {
83    return reference_;
84  }
85
86  static ObjectReference<kPoisonReferences, MirrorType> FromMirrorPtr(MirrorType* mirror_ptr)
87      REQUIRES_SHARED(Locks::mutator_lock_) {
88    return ObjectReference<kPoisonReferences, MirrorType>(mirror_ptr);
89  }
90
91 protected:
92  explicit ObjectReference(MirrorType* mirror_ptr) REQUIRES_SHARED(Locks::mutator_lock_)
93      : reference_(Compression::Compress(mirror_ptr)) {
94  }
95
96  // The encoded reference to a mirror::Object.
97  uint32_t reference_;
98};
99
100// References between objects within the managed heap.
101// Similar API to ObjectReference, but not a value type. Supports atomic access.
102template<class MirrorType>
103class MANAGED HeapReference {
104 private:
105  using Compression = PtrCompression<kPoisonHeapReferences, MirrorType>;
106
107 public:
108  HeapReference() REQUIRES_SHARED(Locks::mutator_lock_) : HeapReference(nullptr) {}
109
110  template <bool kIsVolatile = false>
111  MirrorType* AsMirrorPtr() const REQUIRES_SHARED(Locks::mutator_lock_) {
112    return Compression::Decompress(
113        kIsVolatile ? reference_.LoadSequentiallyConsistent() : reference_.LoadJavaData());
114  }
115
116  template <bool kIsVolatile = false>
117  void Assign(MirrorType* other) REQUIRES_SHARED(Locks::mutator_lock_) {
118    if (kIsVolatile) {
119      reference_.StoreSequentiallyConsistent(Compression::Compress(other));
120    } else {
121      reference_.StoreJavaData(Compression::Compress(other));
122    }
123  }
124
125  template <bool kIsVolatile = false>
126  void Assign(ObjPtr<MirrorType> ptr) REQUIRES_SHARED(Locks::mutator_lock_);
127
128  void Clear() {
129    reference_.StoreJavaData(0);
130    DCHECK(IsNull());
131  }
132
133  bool IsNull() const {
134    return reference_.LoadJavaData() == 0;
135  }
136
137  static HeapReference<MirrorType> FromMirrorPtr(MirrorType* mirror_ptr)
138      REQUIRES_SHARED(Locks::mutator_lock_) {
139    return HeapReference<MirrorType>(mirror_ptr);
140  }
141
142  bool CasWeakRelaxed(MirrorType* old_ptr, MirrorType* new_ptr)
143      REQUIRES_SHARED(Locks::mutator_lock_);
144
145 private:
146  explicit HeapReference(MirrorType* mirror_ptr) REQUIRES_SHARED(Locks::mutator_lock_)
147      : reference_(Compression::Compress(mirror_ptr)) {}
148
149  // The encoded reference to a mirror::Object. Atomically updateable.
150  Atomic<uint32_t> reference_;
151};
152
153static_assert(sizeof(mirror::HeapReference<mirror::Object>) == kHeapReferenceSize,
154              "heap reference size does not match");
155
156// Standard compressed reference used in the runtime. Used for StackReference and GC roots.
157template<class MirrorType>
158class MANAGED CompressedReference : public mirror::ObjectReference<false, MirrorType> {
159 public:
160  CompressedReference<MirrorType>() REQUIRES_SHARED(Locks::mutator_lock_)
161      : mirror::ObjectReference<false, MirrorType>(nullptr) {}
162
163  static CompressedReference<MirrorType> FromMirrorPtr(MirrorType* p)
164      REQUIRES_SHARED(Locks::mutator_lock_) {
165    return CompressedReference<MirrorType>(p);
166  }
167
168 private:
169  explicit CompressedReference(MirrorType* p) REQUIRES_SHARED(Locks::mutator_lock_)
170      : mirror::ObjectReference<false, MirrorType>(p) {}
171};
172
173}  // namespace mirror
174}  // namespace art
175
176#endif  // ART_RUNTIME_MIRROR_OBJECT_REFERENCE_H_
177