blob: 7988af7f6b847acefc2341fe8d0f49b982ed6101 [file] [log] [blame]
Mathieu Chartier78f7b4c2014-05-06 10:57:27 -07001/*
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#include "reference_processor.h"
18
19#include "mirror/object-inl.h"
20#include "mirror/reference-inl.h"
21#include "reflection.h"
22#include "ScopedLocalRef.h"
23#include "scoped_thread_state_change.h"
24#include "well_known_classes.h"
25
26namespace art {
27namespace gc {
28
29ReferenceProcessor::ReferenceProcessor()
30 : process_references_args_(nullptr, nullptr, nullptr), slow_path_enabled_(false),
Mathieu Chartier2d1ab0a2014-05-08 15:27:31 -070031 preserving_references_(false), lock_("reference processor lock", kReferenceProcessorLock),
Mathieu Chartier78f7b4c2014-05-06 10:57:27 -070032 condition_("reference processor condition", lock_) {
33}
34
35void ReferenceProcessor::EnableSlowPath() {
36 Locks::mutator_lock_->AssertExclusiveHeld(Thread::Current());
37 slow_path_enabled_ = true;
38}
39
40void ReferenceProcessor::DisableSlowPath(Thread* self) {
41 slow_path_enabled_ = false;
Mathieu Chartier78f7b4c2014-05-06 10:57:27 -070042 condition_.Broadcast(self);
43}
44
45mirror::Object* ReferenceProcessor::GetReferent(Thread* self, mirror::Reference* reference) {
46 mirror::Object* const referent = reference->GetReferent();
47 if (LIKELY(!slow_path_enabled_)) {
48 return referent;
49 }
50 // Another fast path, the referent is cleared, we can just return null since there is no scenario
51 // where it becomes non-null.
52 if (referent == nullptr) {
53 return nullptr;
54 }
55 MutexLock mu(self, lock_);
56 while (slow_path_enabled_) {
Mathieu Chartier2175f522014-05-09 11:01:06 -070057 mirror::Object* const referent = reference->GetReferent();
58 // If the referent became cleared, return it.
59 if (referent == nullptr) {
60 return nullptr;
61 }
Mathieu Chartier78f7b4c2014-05-06 10:57:27 -070062 // Try to see if the referent is already marked by using the is_marked_callback. We can return
63 // it to the mutator as long as the GC is not preserving references. If the GC is
Mathieu Chartier78f7b4c2014-05-06 10:57:27 -070064 IsMarkedCallback* const is_marked_callback = process_references_args_.is_marked_callback_;
Fred Shih530e1b52014-06-09 15:19:54 -070065 if (LIKELY(is_marked_callback != nullptr)) {
Mathieu Chartier78f7b4c2014-05-06 10:57:27 -070066 mirror::Object* const obj = is_marked_callback(referent, process_references_args_.arg_);
67 // If it's null it means not marked, but it could become marked if the referent is reachable
Fred Shih530e1b52014-06-09 15:19:54 -070068 // by finalizer referents. So we can not return in this case and must block. Otherwise, we
69 // can return it to the mutator as long as the GC is not preserving references, in which
70 // case only black nodes can be safely returned. If the GC is preserving references, the
71 // mutator could take a white field from a grey or white node and move it somewhere else
72 // in the heap causing corruption since this field would get swept.
Mathieu Chartier78f7b4c2014-05-06 10:57:27 -070073 if (obj != nullptr) {
Fred Shih530e1b52014-06-09 15:19:54 -070074 if (!preserving_references_ ||
75 (LIKELY(!reference->IsFinalizerReferenceInstance()) && !reference->IsEnqueued())) {
76 return obj;
77 }
Mathieu Chartier78f7b4c2014-05-06 10:57:27 -070078 }
79 }
Mathieu Chartier2d1ab0a2014-05-08 15:27:31 -070080 condition_.WaitHoldingLocks(self);
Mathieu Chartier78f7b4c2014-05-06 10:57:27 -070081 }
82 return reference->GetReferent();
83}
84
85mirror::Object* ReferenceProcessor::PreserveSoftReferenceCallback(mirror::Object* obj, void* arg) {
86 auto* const args = reinterpret_cast<ProcessReferencesArgs*>(arg);
87 // TODO: Not preserve all soft references.
88 return args->mark_callback_(obj, args->arg_);
89}
90
91void ReferenceProcessor::StartPreservingReferences(Thread* self) {
92 MutexLock mu(self, lock_);
93 preserving_references_ = true;
94}
95
96void ReferenceProcessor::StopPreservingReferences(Thread* self) {
97 MutexLock mu(self, lock_);
98 preserving_references_ = false;
99 // We are done preserving references, some people who are blocked may see a marked referent.
100 condition_.Broadcast(self);
101}
102
103// Process reference class instances and schedule finalizations.
104void ReferenceProcessor::ProcessReferences(bool concurrent, TimingLogger* timings,
105 bool clear_soft_references,
106 IsMarkedCallback* is_marked_callback,
107 MarkObjectCallback* mark_object_callback,
108 ProcessMarkStackCallback* process_mark_stack_callback,
109 void* arg) {
110 Thread* self = Thread::Current();
111 {
112 MutexLock mu(self, lock_);
113 process_references_args_.is_marked_callback_ = is_marked_callback;
114 process_references_args_.mark_callback_ = mark_object_callback;
115 process_references_args_.arg_ = arg;
Mathieu Chartier2175f522014-05-09 11:01:06 -0700116 CHECK_EQ(slow_path_enabled_, concurrent) << "Slow path must be enabled iff concurrent";
Mathieu Chartier78f7b4c2014-05-06 10:57:27 -0700117 }
Mathieu Chartier2175f522014-05-09 11:01:06 -0700118 timings->StartSplit(concurrent ? "ProcessReferences" : "(Paused)ProcessReferences");
Mathieu Chartier78f7b4c2014-05-06 10:57:27 -0700119 // Unless required to clear soft references with white references, preserve some white referents.
120 if (!clear_soft_references) {
Fred Shih530e1b52014-06-09 15:19:54 -0700121 TimingLogger::ScopedSplit split(concurrent ? "ForwardSoftReferences" :
122 "(Paused)ForwardSoftReferences", timings);
Mathieu Chartier78f7b4c2014-05-06 10:57:27 -0700123 if (concurrent) {
124 StartPreservingReferences(self);
125 }
Fred Shih530e1b52014-06-09 15:19:54 -0700126
127 soft_reference_queue_.ForwardSoftReferences(&PreserveSoftReferenceCallback,
128 &process_references_args_);
Mathieu Chartier78f7b4c2014-05-06 10:57:27 -0700129 process_mark_stack_callback(arg);
130 if (concurrent) {
131 StopPreservingReferences(self);
132 }
133 }
134 // Clear all remaining soft and weak references with white referents.
135 soft_reference_queue_.ClearWhiteReferences(cleared_references_, is_marked_callback, arg);
136 weak_reference_queue_.ClearWhiteReferences(cleared_references_, is_marked_callback, arg);
137 {
138 TimingLogger::ScopedSplit split(concurrent ? "EnqueueFinalizerReferences" :
139 "(Paused)EnqueueFinalizerReferences", timings);
140 if (concurrent) {
141 StartPreservingReferences(self);
142 }
143 // Preserve all white objects with finalize methods and schedule them for finalization.
144 finalizer_reference_queue_.EnqueueFinalizerReferences(cleared_references_, is_marked_callback,
145 mark_object_callback, arg);
146 process_mark_stack_callback(arg);
147 if (concurrent) {
148 StopPreservingReferences(self);
149 }
150 }
151 // Clear all finalizer referent reachable soft and weak references with white referents.
152 soft_reference_queue_.ClearWhiteReferences(cleared_references_, is_marked_callback, arg);
153 weak_reference_queue_.ClearWhiteReferences(cleared_references_, is_marked_callback, arg);
154 // Clear all phantom references with white referents.
155 phantom_reference_queue_.ClearWhiteReferences(cleared_references_, is_marked_callback, arg);
156 // At this point all reference queues other than the cleared references should be empty.
157 DCHECK(soft_reference_queue_.IsEmpty());
158 DCHECK(weak_reference_queue_.IsEmpty());
159 DCHECK(finalizer_reference_queue_.IsEmpty());
160 DCHECK(phantom_reference_queue_.IsEmpty());
Mathieu Chartier2175f522014-05-09 11:01:06 -0700161 {
Mathieu Chartier78f7b4c2014-05-06 10:57:27 -0700162 MutexLock mu(self, lock_);
Mathieu Chartier2175f522014-05-09 11:01:06 -0700163 // Need to always do this since the next GC may be concurrent. Doing this for only concurrent
164 // could result in a stale is_marked_callback_ being called before the reference processing
165 // starts since there is a small window of time where slow_path_enabled_ is enabled but the
166 // callback isn't yet set.
167 process_references_args_.is_marked_callback_ = nullptr;
168 if (concurrent) {
169 // Done processing, disable the slow path and broadcast to the waiters.
170 DisableSlowPath(self);
171 }
Mathieu Chartier78f7b4c2014-05-06 10:57:27 -0700172 }
173 timings->EndSplit();
174}
175
176// Process the "referent" field in a java.lang.ref.Reference. If the referent has not yet been
177// marked, put it on the appropriate list in the heap for later processing.
178void ReferenceProcessor::DelayReferenceReferent(mirror::Class* klass, mirror::Reference* ref,
179 IsMarkedCallback is_marked_callback, void* arg) {
180 // klass can be the class of the old object if the visitor already updated the class of ref.
181 DCHECK(klass->IsReferenceClass());
Hiroshi Yamauchibfff21a2014-05-09 12:21:15 -0700182 mirror::Object* referent = ref->GetReferent<kWithoutReadBarrier>();
Mathieu Chartier78f7b4c2014-05-06 10:57:27 -0700183 if (referent != nullptr) {
184 mirror::Object* forward_address = is_marked_callback(referent, arg);
185 // Null means that the object is not currently marked.
186 if (forward_address == nullptr) {
187 Thread* self = Thread::Current();
188 // TODO: Remove these locks, and use atomic stacks for storing references?
189 // We need to check that the references haven't already been enqueued since we can end up
190 // scanning the same reference multiple times due to dirty cards.
191 if (klass->IsSoftReferenceClass()) {
192 soft_reference_queue_.AtomicEnqueueIfNotEnqueued(self, ref);
193 } else if (klass->IsWeakReferenceClass()) {
194 weak_reference_queue_.AtomicEnqueueIfNotEnqueued(self, ref);
195 } else if (klass->IsFinalizerReferenceClass()) {
196 finalizer_reference_queue_.AtomicEnqueueIfNotEnqueued(self, ref);
197 } else if (klass->IsPhantomReferenceClass()) {
198 phantom_reference_queue_.AtomicEnqueueIfNotEnqueued(self, ref);
199 } else {
200 LOG(FATAL) << "Invalid reference type " << PrettyClass(klass) << " " << std::hex
201 << klass->GetAccessFlags();
202 }
203 } else if (referent != forward_address) {
204 // Referent is already marked and we need to update it.
205 ref->SetReferent<false>(forward_address);
206 }
207 }
208}
209
210void ReferenceProcessor::EnqueueClearedReferences() {
211 Thread* self = Thread::Current();
212 Locks::mutator_lock_->AssertNotHeld(self);
213 if (!cleared_references_.IsEmpty()) {
214 // When a runtime isn't started there are no reference queues to care about so ignore.
215 if (LIKELY(Runtime::Current()->IsStarted())) {
216 ScopedObjectAccess soa(self);
217 ScopedLocalRef<jobject> arg(self->GetJniEnv(),
218 soa.AddLocalReference<jobject>(cleared_references_.GetList()));
219 jvalue args[1];
220 args[0].l = arg.get();
221 InvokeWithJValues(soa, nullptr, WellKnownClasses::java_lang_ref_ReferenceQueue_add, args);
222 }
223 cleared_references_.Clear();
224 }
225}
226
227} // namespace gc
228} // namespace art