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