blob: 95d9a1d31530066d55f8ea55dc960ca39966b082 [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"
22#include "gc/heap.h"
23#include "mirror/class.h"
24#include "object_callbacks.h"
25#include "object_tagging.h"
26#include "obj_ptr-inl.h"
27#include "runtime.h"
28#include "scoped_thread_state_change-inl.h"
29#include "thread-inl.h"
30
31namespace openjdkjvmti {
32
33struct IterateThroughHeapData {
34 IterateThroughHeapData(HeapUtil* _heap_util,
35 jint heap_filter,
36 art::ObjPtr<art::mirror::Class> klass,
37 const jvmtiHeapCallbacks* _callbacks,
38 const void* _user_data)
39 : heap_util(_heap_util),
40 filter_klass(klass),
41 callbacks(_callbacks),
42 user_data(_user_data),
43 filter_out_tagged((heap_filter & JVMTI_HEAP_FILTER_TAGGED) != 0),
44 filter_out_untagged((heap_filter & JVMTI_HEAP_FILTER_UNTAGGED) != 0),
45 filter_out_class_tagged((heap_filter & JVMTI_HEAP_FILTER_CLASS_TAGGED) != 0),
46 filter_out_class_untagged((heap_filter & JVMTI_HEAP_FILTER_CLASS_UNTAGGED) != 0),
47 any_filter(filter_out_tagged ||
48 filter_out_untagged ||
49 filter_out_class_tagged ||
50 filter_out_class_untagged),
51 stop_reports(false) {
52 }
53
54 bool ShouldReportByHeapFilter(jlong tag, jlong class_tag) {
55 if (!any_filter) {
56 return true;
57 }
58
59 if ((tag == 0 && filter_out_untagged) || (tag != 0 && filter_out_tagged)) {
60 return false;
61 }
62
63 if ((class_tag == 0 && filter_out_class_untagged) ||
64 (class_tag != 0 && filter_out_class_tagged)) {
65 return false;
66 }
67
68 return true;
69 }
70
71 HeapUtil* heap_util;
72 art::ObjPtr<art::mirror::Class> filter_klass;
73 const jvmtiHeapCallbacks* callbacks;
74 const void* user_data;
75 const bool filter_out_tagged;
76 const bool filter_out_untagged;
77 const bool filter_out_class_tagged;
78 const bool filter_out_class_untagged;
79 const bool any_filter;
80
81 bool stop_reports;
82};
83
84static void IterateThroughHeapObjectCallback(art::mirror::Object* obj, void* arg)
85 REQUIRES_SHARED(art::Locks::mutator_lock_) {
86 IterateThroughHeapData* ithd = reinterpret_cast<IterateThroughHeapData*>(arg);
87 // Early return, as we can't really stop visiting.
88 if (ithd->stop_reports) {
89 return;
90 }
91
92 art::ScopedAssertNoThreadSuspension no_suspension("IterateThroughHeapCallback");
93
94 jlong tag = 0;
95 ithd->heap_util->GetTags()->GetTag(obj, &tag);
96
97 jlong class_tag = 0;
98 art::ObjPtr<art::mirror::Class> klass = obj->GetClass();
99 ithd->heap_util->GetTags()->GetTag(klass.Ptr(), &class_tag);
100 // For simplicity, even if we find a tag = 0, assume 0 = not tagged.
101
102 if (!ithd->ShouldReportByHeapFilter(tag, class_tag)) {
103 return;
104 }
105
106 // TODO: Handle array_primitive_value_callback.
107
108 if (ithd->filter_klass != nullptr) {
109 if (ithd->filter_klass != klass) {
110 return;
111 }
112 }
113
114 jlong size = obj->SizeOf();
115
116 jint length = -1;
117 if (obj->IsArrayInstance()) {
118 length = obj->AsArray()->GetLength();
119 }
120
121 jlong saved_tag = tag;
122 jint ret = ithd->callbacks->heap_iteration_callback(class_tag,
123 size,
124 &tag,
125 length,
126 const_cast<void*>(ithd->user_data));
127
128 if (tag != saved_tag) {
129 ithd->heap_util->GetTags()->Set(obj, tag);
130 }
131
132 ithd->stop_reports = (ret & JVMTI_VISIT_ABORT) != 0;
133
134 // TODO Implement array primitive and string primitive callback.
135 // TODO Implement primitive field callback.
136}
137
138jvmtiError HeapUtil::IterateThroughHeap(jvmtiEnv* env ATTRIBUTE_UNUSED,
139 jint heap_filter,
140 jclass klass,
141 const jvmtiHeapCallbacks* callbacks,
142 const void* user_data) {
143 if (callbacks == nullptr) {
144 return ERR(NULL_POINTER);
145 }
146
147 if (callbacks->array_primitive_value_callback != nullptr) {
148 // TODO: Implement.
149 return ERR(NOT_IMPLEMENTED);
150 }
151
152 art::Thread* self = art::Thread::Current();
153 art::ScopedObjectAccess soa(self); // Now we know we have the shared lock.
154
155 IterateThroughHeapData ithd(this,
156 heap_filter,
157 soa.Decode<art::mirror::Class>(klass),
158 callbacks,
159 user_data);
160
161 art::Runtime::Current()->GetHeap()->VisitObjects(IterateThroughHeapObjectCallback, &ithd);
162
163 return ERR(NONE);
164}
165
166} // namespace openjdkjvmti