blob: 6b207430ff0c3cd086c7e73e75b2b189db4c55a7 [file] [log] [blame]
Andreas Gampee54d9922016-10-11 19:55:37 -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
Andreas Gampeba8df692016-11-01 10:30:44 -070017#include "ti_heap.h"
Andreas Gampee54d9922016-10-11 19:55:37 -070018
19#include "art_jvmti.h"
20#include "base/macros.h"
21#include "base/mutex.h"
Andreas Gampeaa8b60c2016-10-12 12:51:25 -070022#include "class_linker.h"
Andreas Gampee54d9922016-10-11 19:55:37 -070023#include "gc/heap.h"
Andreas Gampeaa8b60c2016-10-12 12:51:25 -070024#include "jni_env_ext.h"
Andreas Gampee54d9922016-10-11 19:55:37 -070025#include "mirror/class.h"
26#include "object_callbacks.h"
27#include "object_tagging.h"
28#include "obj_ptr-inl.h"
29#include "runtime.h"
30#include "scoped_thread_state_change-inl.h"
31#include "thread-inl.h"
32
33namespace openjdkjvmti {
34
35struct IterateThroughHeapData {
36 IterateThroughHeapData(HeapUtil* _heap_util,
37 jint heap_filter,
38 art::ObjPtr<art::mirror::Class> klass,
39 const jvmtiHeapCallbacks* _callbacks,
40 const void* _user_data)
41 : heap_util(_heap_util),
42 filter_klass(klass),
43 callbacks(_callbacks),
44 user_data(_user_data),
45 filter_out_tagged((heap_filter & JVMTI_HEAP_FILTER_TAGGED) != 0),
46 filter_out_untagged((heap_filter & JVMTI_HEAP_FILTER_UNTAGGED) != 0),
47 filter_out_class_tagged((heap_filter & JVMTI_HEAP_FILTER_CLASS_TAGGED) != 0),
48 filter_out_class_untagged((heap_filter & JVMTI_HEAP_FILTER_CLASS_UNTAGGED) != 0),
49 any_filter(filter_out_tagged ||
50 filter_out_untagged ||
51 filter_out_class_tagged ||
52 filter_out_class_untagged),
53 stop_reports(false) {
54 }
55
56 bool ShouldReportByHeapFilter(jlong tag, jlong class_tag) {
57 if (!any_filter) {
58 return true;
59 }
60
61 if ((tag == 0 && filter_out_untagged) || (tag != 0 && filter_out_tagged)) {
62 return false;
63 }
64
65 if ((class_tag == 0 && filter_out_class_untagged) ||
66 (class_tag != 0 && filter_out_class_tagged)) {
67 return false;
68 }
69
70 return true;
71 }
72
73 HeapUtil* heap_util;
74 art::ObjPtr<art::mirror::Class> filter_klass;
75 const jvmtiHeapCallbacks* callbacks;
76 const void* user_data;
77 const bool filter_out_tagged;
78 const bool filter_out_untagged;
79 const bool filter_out_class_tagged;
80 const bool filter_out_class_untagged;
81 const bool any_filter;
82
83 bool stop_reports;
84};
85
86static void IterateThroughHeapObjectCallback(art::mirror::Object* obj, void* arg)
87 REQUIRES_SHARED(art::Locks::mutator_lock_) {
88 IterateThroughHeapData* ithd = reinterpret_cast<IterateThroughHeapData*>(arg);
89 // Early return, as we can't really stop visiting.
90 if (ithd->stop_reports) {
91 return;
92 }
93
94 art::ScopedAssertNoThreadSuspension no_suspension("IterateThroughHeapCallback");
95
96 jlong tag = 0;
97 ithd->heap_util->GetTags()->GetTag(obj, &tag);
98
99 jlong class_tag = 0;
100 art::ObjPtr<art::mirror::Class> klass = obj->GetClass();
101 ithd->heap_util->GetTags()->GetTag(klass.Ptr(), &class_tag);
102 // For simplicity, even if we find a tag = 0, assume 0 = not tagged.
103
104 if (!ithd->ShouldReportByHeapFilter(tag, class_tag)) {
105 return;
106 }
107
108 // TODO: Handle array_primitive_value_callback.
109
110 if (ithd->filter_klass != nullptr) {
111 if (ithd->filter_klass != klass) {
112 return;
113 }
114 }
115
116 jlong size = obj->SizeOf();
117
118 jint length = -1;
119 if (obj->IsArrayInstance()) {
120 length = obj->AsArray()->GetLength();
121 }
122
123 jlong saved_tag = tag;
124 jint ret = ithd->callbacks->heap_iteration_callback(class_tag,
125 size,
126 &tag,
127 length,
128 const_cast<void*>(ithd->user_data));
129
130 if (tag != saved_tag) {
131 ithd->heap_util->GetTags()->Set(obj, tag);
132 }
133
134 ithd->stop_reports = (ret & JVMTI_VISIT_ABORT) != 0;
135
136 // TODO Implement array primitive and string primitive callback.
137 // TODO Implement primitive field callback.
138}
139
140jvmtiError HeapUtil::IterateThroughHeap(jvmtiEnv* env ATTRIBUTE_UNUSED,
141 jint heap_filter,
142 jclass klass,
143 const jvmtiHeapCallbacks* callbacks,
144 const void* user_data) {
145 if (callbacks == nullptr) {
146 return ERR(NULL_POINTER);
147 }
148
149 if (callbacks->array_primitive_value_callback != nullptr) {
150 // TODO: Implement.
151 return ERR(NOT_IMPLEMENTED);
152 }
153
154 art::Thread* self = art::Thread::Current();
155 art::ScopedObjectAccess soa(self); // Now we know we have the shared lock.
156
157 IterateThroughHeapData ithd(this,
158 heap_filter,
159 soa.Decode<art::mirror::Class>(klass),
160 callbacks,
161 user_data);
162
163 art::Runtime::Current()->GetHeap()->VisitObjects(IterateThroughHeapObjectCallback, &ithd);
164
165 return ERR(NONE);
166}
167
Andreas Gampeaa8b60c2016-10-12 12:51:25 -0700168jvmtiError HeapUtil::GetLoadedClasses(jvmtiEnv* env,
169 jint* class_count_ptr,
170 jclass** classes_ptr) {
171 if (class_count_ptr == nullptr || classes_ptr == nullptr) {
172 return ERR(NULL_POINTER);
173 }
174
175 class ReportClassVisitor : public art::ClassVisitor {
176 public:
177 explicit ReportClassVisitor(art::Thread* self) : self_(self) {}
178
Mathieu Chartier28357fa2016-10-18 16:27:40 -0700179 bool operator()(art::ObjPtr<art::mirror::Class> klass)
180 OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) {
Andreas Gampeef54d8d2016-10-25 09:55:53 -0700181 classes_.push_back(self_->GetJniEnv()->AddLocalReference<jclass>(klass));
Andreas Gampeaa8b60c2016-10-12 12:51:25 -0700182 return true;
183 }
184
185 art::Thread* self_;
186 std::vector<jclass> classes_;
187 };
188
189 art::Thread* self = art::Thread::Current();
190 ReportClassVisitor rcv(self);
191 {
192 art::ScopedObjectAccess soa(self);
193 art::Runtime::Current()->GetClassLinker()->VisitClasses(&rcv);
194 }
195
196 size_t size = rcv.classes_.size();
197 jclass* classes = nullptr;
198 jvmtiError alloc_ret = env->Allocate(static_cast<jlong>(size * sizeof(jclass)),
199 reinterpret_cast<unsigned char**>(&classes));
200 if (alloc_ret != ERR(NONE)) {
201 return alloc_ret;
202 }
203
204 for (size_t i = 0; i < size; ++i) {
205 classes[i] = rcv.classes_[i];
206 }
207 *classes_ptr = classes;
208 *class_count_ptr = static_cast<jint>(size);
209
210 return ERR(NONE);
211}
212
Andreas Gampe8da6d032016-10-31 19:31:03 -0700213jvmtiError HeapUtil::ForceGarbageCollection(jvmtiEnv* env ATTRIBUTE_UNUSED) {
214 art::Runtime::Current()->GetHeap()->CollectGarbage(false);
215
216 return ERR(NONE);
217}
218
Andreas Gampee54d9922016-10-11 19:55:37 -0700219} // namespace openjdkjvmti