blob: d74026cc57857a8ff2959134d2be2d47a35289b1 [file] [log] [blame]
Andreas Gampe8da6d032016-10-31 19:31:03 -07001/*
2 * Copyright (C) 2013 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 "heaps.h"
18
Andreas Gampe70bfc8a2016-11-03 11:04:15 -070019#include <inttypes.h>
Andreas Gampe8da6d032016-10-31 19:31:03 -070020#include <stdio.h>
21#include <string.h>
22
Andreas Gampe70bfc8a2016-11-03 11:04:15 -070023#include <vector>
24
25#include "base/logging.h"
Andreas Gampe8da6d032016-10-31 19:31:03 -070026#include "base/macros.h"
Andreas Gampe70bfc8a2016-11-03 11:04:15 -070027#include "base/stringprintf.h"
Andreas Gampe8da6d032016-10-31 19:31:03 -070028#include "jni.h"
29#include "openjdkjvmti/jvmti.h"
Andreas Gampe70bfc8a2016-11-03 11:04:15 -070030#include "ti-agent/common_helper.h"
Andreas Gampe8da6d032016-10-31 19:31:03 -070031#include "ti-agent/common_load.h"
32
33namespace art {
34namespace Test913Heaps {
35
36extern "C" JNIEXPORT void JNICALL Java_Main_forceGarbageCollection(JNIEnv* env ATTRIBUTE_UNUSED,
37 jclass klass ATTRIBUTE_UNUSED) {
38 jvmtiError ret = jvmti_env->ForceGarbageCollection();
39 if (ret != JVMTI_ERROR_NONE) {
40 char* err;
41 jvmti_env->GetErrorName(ret, &err);
42 printf("Error forcing a garbage collection: %s\n", err);
43 }
44}
45
Andreas Gampe70bfc8a2016-11-03 11:04:15 -070046class IterationConfig {
47 public:
48 IterationConfig() {}
49 virtual ~IterationConfig() {}
50
51 virtual jint Handle(jvmtiHeapReferenceKind reference_kind,
52 const jvmtiHeapReferenceInfo* reference_info,
53 jlong class_tag,
54 jlong referrer_class_tag,
55 jlong size,
56 jlong* tag_ptr,
57 jlong* referrer_tag_ptr,
58 jint length,
59 void* user_data) = 0;
60};
61
62static jint JNICALL HeapReferenceCallback(jvmtiHeapReferenceKind reference_kind,
63 const jvmtiHeapReferenceInfo* reference_info,
64 jlong class_tag,
65 jlong referrer_class_tag,
66 jlong size,
67 jlong* tag_ptr,
68 jlong* referrer_tag_ptr,
69 jint length,
70 void* user_data) {
71 IterationConfig* config = reinterpret_cast<IterationConfig*>(user_data);
72 return config->Handle(reference_kind,
73 reference_info,
74 class_tag,
75 referrer_class_tag,
76 size,
77 tag_ptr,
78 referrer_tag_ptr,
79 length,
80 user_data);
81}
82
83static bool Run(jint heap_filter,
84 jclass klass_filter,
85 jobject initial_object,
86 IterationConfig* config) {
87 jvmtiHeapCallbacks callbacks;
88 memset(&callbacks, 0, sizeof(jvmtiHeapCallbacks));
89 callbacks.heap_reference_callback = HeapReferenceCallback;
90
91 jvmtiError ret = jvmti_env->FollowReferences(heap_filter,
92 klass_filter,
93 initial_object,
94 &callbacks,
95 config);
96 if (ret != JVMTI_ERROR_NONE) {
97 char* err;
98 jvmti_env->GetErrorName(ret, &err);
99 printf("Failure running FollowReferences: %s\n", err);
100 return false;
101 }
102 return true;
103}
104
105extern "C" JNIEXPORT jobjectArray JNICALL Java_Main_followReferences(JNIEnv* env,
106 jclass klass ATTRIBUTE_UNUSED,
107 jint heap_filter,
108 jclass klass_filter,
109 jobject initial_object,
110 jint stop_after,
111 jint follow_set,
112 jobject jniRef) {
113 class PrintIterationConfig FINAL : public IterationConfig {
114 public:
115 PrintIterationConfig(jint _stop_after, jint _follow_set)
116 : counter_(0),
117 stop_after_(_stop_after),
118 follow_set_(_follow_set) {
119 }
120
121 jint Handle(jvmtiHeapReferenceKind reference_kind,
122 const jvmtiHeapReferenceInfo* reference_info,
123 jlong class_tag,
124 jlong referrer_class_tag,
125 jlong size,
126 jlong* tag_ptr,
127 jlong* referrer_tag_ptr,
128 jint length,
129 void* user_data ATTRIBUTE_UNUSED) OVERRIDE {
130 jlong tag = *tag_ptr;
131 // Only check tagged objects.
132 if (tag == 0) {
133 return JVMTI_VISIT_OBJECTS;
134 }
135
136 Print(reference_kind,
137 reference_info,
138 class_tag,
139 referrer_class_tag,
140 size,
141 tag_ptr,
142 referrer_tag_ptr,
143 length);
144
145 counter_++;
146 if (counter_ == stop_after_) {
147 return JVMTI_VISIT_ABORT;
148 }
149
150 if (tag > 0 && tag < 32) {
151 bool should_visit_references = (follow_set_ & (1 << static_cast<int32_t>(tag))) != 0;
152 return should_visit_references ? JVMTI_VISIT_OBJECTS : 0;
153 }
154
155 return JVMTI_VISIT_OBJECTS;
156 }
157
158 void Print(jvmtiHeapReferenceKind reference_kind,
159 const jvmtiHeapReferenceInfo* reference_info,
160 jlong class_tag,
161 jlong referrer_class_tag,
162 jlong size,
163 jlong* tag_ptr,
164 jlong* referrer_tag_ptr,
165 jint length) {
166 std::string referrer_str;
167 if (referrer_tag_ptr == nullptr) {
168 referrer_str = "root@root";
169 } else {
170 referrer_str = StringPrintf("%" PRId64 "@%" PRId64, *referrer_tag_ptr, referrer_class_tag);
171 }
172
173 jlong adapted_size = size;
174 if (*tag_ptr >= 1000) {
175 // This is a class or interface, the size of which will be dependent on the architecture.
176 // Do not print the size, but detect known values and "normalize" for the golden file.
177 if ((sizeof(void*) == 4 && size == 180) || (sizeof(void*) == 8 && size == 232)) {
178 adapted_size = 123;
179 }
180 }
181
182 lines_.push_back(
183 StringPrintf("%s --(%s)--> %" PRId64 "@%" PRId64 " [size=%" PRId64 ", length=%d]",
184 referrer_str.c_str(),
185 GetReferenceTypeStr(reference_kind, reference_info).c_str(),
186 *tag_ptr,
187 class_tag,
188 adapted_size,
189 length));
190 }
191
192 static std::string GetReferenceTypeStr(jvmtiHeapReferenceKind reference_kind,
193 const jvmtiHeapReferenceInfo* reference_info) {
194 switch (reference_kind) {
195 case JVMTI_HEAP_REFERENCE_CLASS:
196 return "class";
197 case JVMTI_HEAP_REFERENCE_FIELD:
198 return StringPrintf("field@%d", reference_info->field.index);
199 case JVMTI_HEAP_REFERENCE_ARRAY_ELEMENT:
200 return StringPrintf("array-element@%d", reference_info->array.index);
201 case JVMTI_HEAP_REFERENCE_CLASS_LOADER:
202 return "classloader";
203 case JVMTI_HEAP_REFERENCE_SIGNERS:
204 return "signers";
205 case JVMTI_HEAP_REFERENCE_PROTECTION_DOMAIN:
206 return "protection-domain";
207 case JVMTI_HEAP_REFERENCE_INTERFACE:
208 return "interface";
209 case JVMTI_HEAP_REFERENCE_STATIC_FIELD:
210 return StringPrintf("static-field@%d", reference_info->field.index);
211 case JVMTI_HEAP_REFERENCE_CONSTANT_POOL:
212 return "constant-pool";
213 case JVMTI_HEAP_REFERENCE_SUPERCLASS:
214 return "superclass";
215 case JVMTI_HEAP_REFERENCE_JNI_GLOBAL:
216 return "jni-global";
217 case JVMTI_HEAP_REFERENCE_SYSTEM_CLASS:
218 return "system-class";
219 case JVMTI_HEAP_REFERENCE_MONITOR:
220 return "monitor";
221 case JVMTI_HEAP_REFERENCE_STACK_LOCAL:
222 return "stack-local";
223 case JVMTI_HEAP_REFERENCE_JNI_LOCAL:
224 return "jni-local";
225 case JVMTI_HEAP_REFERENCE_THREAD:
226 return "thread";
227 case JVMTI_HEAP_REFERENCE_OTHER:
228 return "other";
229 }
230 return "unknown";
231 }
232
233 const std::vector<std::string>& GetLines() const {
234 return lines_;
235 }
236
237 private:
238 jint counter_;
239 const jint stop_after_;
240 const jint follow_set_;
241 std::vector<std::string> lines_;
242 };
243
244 // If jniRef isn't null, add a local and a global ref.
245 ScopedLocalRef<jobject> jni_local_ref(env, nullptr);
246 jobject jni_global_ref = nullptr;
247 if (jniRef != nullptr) {
248 jni_local_ref.reset(env->NewLocalRef(jniRef));
249 jni_global_ref = env->NewGlobalRef(jniRef);
250 }
251
252 PrintIterationConfig config(stop_after, follow_set);
253 Run(heap_filter, klass_filter, initial_object, &config);
254
255 const std::vector<std::string>& lines = config.GetLines();
256 jobjectArray ret = CreateObjectArray(env,
257 static_cast<jint>(lines.size()),
258 "java/lang/String",
259 [&](jint i) {
260 return env->NewStringUTF(lines[i].c_str());
261 });
262
263 if (jni_global_ref != nullptr) {
264 env->DeleteGlobalRef(jni_global_ref);
265 }
266
267 return ret;
268}
269
Andreas Gampe8da6d032016-10-31 19:31:03 -0700270// Don't do anything
271jint OnLoad(JavaVM* vm,
272 char* options ATTRIBUTE_UNUSED,
273 void* reserved ATTRIBUTE_UNUSED) {
274 if (vm->GetEnv(reinterpret_cast<void**>(&jvmti_env), JVMTI_VERSION_1_0)) {
275 printf("Unable to get jvmti env!\n");
276 return 1;
277 }
278 return 0;
279}
280
281} // namespace Test913Heaps
282} // namespace art