blob: 9c4fa8d6c01894c8e5f805691690cb08d7692f16 [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
Andreas Gampe46ee31b2016-12-14 10:11:49 -080025#include "android-base/stringprintf.h"
26
Andreas Gampe70bfc8a2016-11-03 11:04:15 -070027#include "base/logging.h"
Andreas Gampe8da6d032016-10-31 19:31:03 -070028#include "base/macros.h"
Andreas Gampe5d139fc2016-11-09 22:54:25 -080029#include "jit/jit.h"
Andreas Gampe8da6d032016-10-31 19:31:03 -070030#include "jni.h"
Andreas Gampe216090d2016-11-15 12:33:18 -080031#include "native_stack_dump.h"
Andreas Gampe8da6d032016-10-31 19:31:03 -070032#include "openjdkjvmti/jvmti.h"
Andreas Gampe5d139fc2016-11-09 22:54:25 -080033#include "runtime.h"
34#include "thread-inl.h"
Andreas Gampe216090d2016-11-15 12:33:18 -080035#include "thread_list.h"
Alex Lighte6574242016-08-17 09:56:24 -070036
Andreas Gampe70bfc8a2016-11-03 11:04:15 -070037#include "ti-agent/common_helper.h"
Andreas Gampe8da6d032016-10-31 19:31:03 -070038#include "ti-agent/common_load.h"
39
40namespace art {
41namespace Test913Heaps {
42
Andreas Gampe46ee31b2016-12-14 10:11:49 -080043using android::base::StringPrintf;
44
Andreas Gampe8da6d032016-10-31 19:31:03 -070045extern "C" JNIEXPORT void JNICALL Java_Main_forceGarbageCollection(JNIEnv* env ATTRIBUTE_UNUSED,
46 jclass klass ATTRIBUTE_UNUSED) {
47 jvmtiError ret = jvmti_env->ForceGarbageCollection();
48 if (ret != JVMTI_ERROR_NONE) {
49 char* err;
50 jvmti_env->GetErrorName(ret, &err);
51 printf("Error forcing a garbage collection: %s\n", err);
52 }
53}
54
Andreas Gampe70bfc8a2016-11-03 11:04:15 -070055class IterationConfig {
56 public:
57 IterationConfig() {}
58 virtual ~IterationConfig() {}
59
60 virtual jint Handle(jvmtiHeapReferenceKind reference_kind,
61 const jvmtiHeapReferenceInfo* reference_info,
62 jlong class_tag,
63 jlong referrer_class_tag,
64 jlong size,
65 jlong* tag_ptr,
66 jlong* referrer_tag_ptr,
67 jint length,
68 void* user_data) = 0;
69};
70
71static jint JNICALL HeapReferenceCallback(jvmtiHeapReferenceKind reference_kind,
72 const jvmtiHeapReferenceInfo* reference_info,
73 jlong class_tag,
74 jlong referrer_class_tag,
75 jlong size,
76 jlong* tag_ptr,
77 jlong* referrer_tag_ptr,
78 jint length,
79 void* user_data) {
80 IterationConfig* config = reinterpret_cast<IterationConfig*>(user_data);
81 return config->Handle(reference_kind,
82 reference_info,
83 class_tag,
84 referrer_class_tag,
85 size,
86 tag_ptr,
87 referrer_tag_ptr,
88 length,
89 user_data);
90}
91
92static bool Run(jint heap_filter,
93 jclass klass_filter,
94 jobject initial_object,
95 IterationConfig* config) {
96 jvmtiHeapCallbacks callbacks;
97 memset(&callbacks, 0, sizeof(jvmtiHeapCallbacks));
98 callbacks.heap_reference_callback = HeapReferenceCallback;
99
100 jvmtiError ret = jvmti_env->FollowReferences(heap_filter,
101 klass_filter,
102 initial_object,
103 &callbacks,
104 config);
105 if (ret != JVMTI_ERROR_NONE) {
106 char* err;
107 jvmti_env->GetErrorName(ret, &err);
108 printf("Failure running FollowReferences: %s\n", err);
109 return false;
110 }
111 return true;
112}
113
114extern "C" JNIEXPORT jobjectArray JNICALL Java_Main_followReferences(JNIEnv* env,
115 jclass klass ATTRIBUTE_UNUSED,
116 jint heap_filter,
117 jclass klass_filter,
118 jobject initial_object,
119 jint stop_after,
120 jint follow_set,
121 jobject jniRef) {
122 class PrintIterationConfig FINAL : public IterationConfig {
123 public:
124 PrintIterationConfig(jint _stop_after, jint _follow_set)
125 : counter_(0),
126 stop_after_(_stop_after),
127 follow_set_(_follow_set) {
128 }
129
130 jint Handle(jvmtiHeapReferenceKind reference_kind,
131 const jvmtiHeapReferenceInfo* reference_info,
132 jlong class_tag,
133 jlong referrer_class_tag,
134 jlong size,
135 jlong* tag_ptr,
136 jlong* referrer_tag_ptr,
137 jint length,
138 void* user_data ATTRIBUTE_UNUSED) OVERRIDE {
139 jlong tag = *tag_ptr;
140 // Only check tagged objects.
141 if (tag == 0) {
142 return JVMTI_VISIT_OBJECTS;
143 }
144
145 Print(reference_kind,
146 reference_info,
147 class_tag,
148 referrer_class_tag,
149 size,
150 tag_ptr,
151 referrer_tag_ptr,
152 length);
153
154 counter_++;
155 if (counter_ == stop_after_) {
156 return JVMTI_VISIT_ABORT;
157 }
158
159 if (tag > 0 && tag < 32) {
160 bool should_visit_references = (follow_set_ & (1 << static_cast<int32_t>(tag))) != 0;
161 return should_visit_references ? JVMTI_VISIT_OBJECTS : 0;
162 }
163
164 return JVMTI_VISIT_OBJECTS;
165 }
166
167 void Print(jvmtiHeapReferenceKind reference_kind,
168 const jvmtiHeapReferenceInfo* reference_info,
169 jlong class_tag,
170 jlong referrer_class_tag,
171 jlong size,
172 jlong* tag_ptr,
173 jlong* referrer_tag_ptr,
174 jint length) {
175 std::string referrer_str;
176 if (referrer_tag_ptr == nullptr) {
177 referrer_str = "root@root";
178 } else {
179 referrer_str = StringPrintf("%" PRId64 "@%" PRId64, *referrer_tag_ptr, referrer_class_tag);
180 }
181
182 jlong adapted_size = size;
183 if (*tag_ptr >= 1000) {
184 // This is a class or interface, the size of which will be dependent on the architecture.
185 // Do not print the size, but detect known values and "normalize" for the golden file.
186 if ((sizeof(void*) == 4 && size == 180) || (sizeof(void*) == 8 && size == 232)) {
187 adapted_size = 123;
188 }
189 }
190
Andreas Gampedce591b2016-11-17 11:23:35 -0800191 std::string referree_str = StringPrintf("%" PRId64 "@%" PRId64, *tag_ptr, class_tag);
192
193 lines_.push_back(CreateElem(referrer_str,
194 referree_str,
195 reference_kind,
196 reference_info,
197 adapted_size,
198 length));
Andreas Gampe216090d2016-11-15 12:33:18 -0800199
200 if (reference_kind == JVMTI_HEAP_REFERENCE_THREAD && *tag_ptr == 1000) {
201 DumpStacks();
202 }
203 }
204
Andreas Gampedce591b2016-11-17 11:23:35 -0800205 std::vector<std::string> GetLines() const {
206 std::vector<std::string> ret;
207 for (const std::unique_ptr<Elem>& e : lines_) {
208 ret.push_back(e->Print());
209 }
210 return ret;
211 }
212
213 private:
214 // We need to postpone some printing, as required functions are not callback-safe.
215 class Elem {
216 public:
217 Elem(const std::string& referrer, const std::string& referree, jlong size, jint length)
218 : referrer_(referrer), referree_(referree), size_(size), length_(length) {}
219 virtual ~Elem() {}
220
221 std::string Print() const {
222 return StringPrintf("%s --(%s)--> %s [size=%" PRId64 ", length=%d]",
223 referrer_.c_str(),
224 PrintArrowType().c_str(),
225 referree_.c_str(),
226 size_,
227 length_);
228 }
229
230 protected:
231 virtual std::string PrintArrowType() const = 0;
232
233 private:
234 std::string referrer_;
235 std::string referree_;
236 jlong size_;
237 jint length_;
238 };
239
Andreas Gampe93c30902016-11-18 13:30:30 -0800240 class JNILocalElement : public Elem {
241 public:
242 JNILocalElement(const std::string& referrer,
243 const std::string& referree,
244 jlong size,
245 jint length,
246 const jvmtiHeapReferenceInfo* reference_info)
247 : Elem(referrer, referree, size, length) {
248 memcpy(&info_, reference_info, sizeof(jvmtiHeapReferenceInfo));
249 }
250
251 protected:
252 std::string PrintArrowType() const OVERRIDE {
253 char* name = nullptr;
254 if (info_.jni_local.method != nullptr) {
255 jvmti_env->GetMethodName(info_.jni_local.method, &name, nullptr, nullptr);
256 }
257 std::string ret = StringPrintf("jni-local[id=%" PRId64 ",tag=%" PRId64 ",depth=%d,"
258 "method=%s]",
259 info_.jni_local.thread_id,
260 info_.jni_local.thread_tag,
261 info_.jni_local.depth,
262 name == nullptr ? "<null>" : name);
263 if (name != nullptr) {
264 jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(name));
265 }
266
267 return ret;
268 }
269
270 private:
271 const std::string string_;
272 jvmtiHeapReferenceInfo info_;
273 };
274
Andreas Gampef10dfcd2016-12-02 14:42:33 -0800275 class StackLocalElement : public Elem {
276 public:
277 StackLocalElement(const std::string& referrer,
278 const std::string& referree,
279 jlong size,
280 jint length,
281 const jvmtiHeapReferenceInfo* reference_info)
282 : Elem(referrer, referree, size, length) {
283 memcpy(&info_, reference_info, sizeof(jvmtiHeapReferenceInfo));
284 }
285
286 protected:
287 std::string PrintArrowType() const OVERRIDE {
288 char* name = nullptr;
289 if (info_.stack_local.method != nullptr) {
290 jvmti_env->GetMethodName(info_.stack_local.method, &name, nullptr, nullptr);
291 }
292 std::string ret = StringPrintf("stack-local[id=%" PRId64 ",tag=%" PRId64 ",depth=%d,"
293 "method=%s,vreg=%d,location=% " PRId64 "]",
294 info_.stack_local.thread_id,
295 info_.stack_local.thread_tag,
296 info_.stack_local.depth,
297 name == nullptr ? "<null>" : name,
298 info_.stack_local.slot,
299 info_.stack_local.location);
300 if (name != nullptr) {
301 jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(name));
302 }
303
304 return ret;
305 }
306
307 private:
308 const std::string string_;
309 jvmtiHeapReferenceInfo info_;
310 };
311
Andreas Gampedce591b2016-11-17 11:23:35 -0800312 // For simple or unimplemented cases.
313 class StringElement : public Elem {
314 public:
315 StringElement(const std::string& referrer,
316 const std::string& referree,
317 jlong size,
318 jint length,
319 const std::string& string)
320 : Elem(referrer, referree, size, length), string_(string) {}
321
322 protected:
323 std::string PrintArrowType() const OVERRIDE {
324 return string_;
325 }
326
327 private:
328 const std::string string_;
329 };
330
331 static std::unique_ptr<Elem> CreateElem(const std::string& referrer,
332 const std::string& referree,
333 jvmtiHeapReferenceKind reference_kind,
334 const jvmtiHeapReferenceInfo* reference_info,
335 jlong size,
336 jint length) {
337 switch (reference_kind) {
338 case JVMTI_HEAP_REFERENCE_CLASS:
339 return std::unique_ptr<Elem>(new StringElement(referrer,
340 referree,
341 size,
342 length,
343 "class"));
344 case JVMTI_HEAP_REFERENCE_FIELD: {
345 std::string tmp = StringPrintf("field@%d", reference_info->field.index);
346 return std::unique_ptr<Elem>(new StringElement(referrer,
347 referree,
348 size,
349 length,
350 tmp));
351 }
352 case JVMTI_HEAP_REFERENCE_ARRAY_ELEMENT: {
353 std::string tmp = StringPrintf("array-element@%d", reference_info->array.index);
354 return std::unique_ptr<Elem>(new StringElement(referrer,
355 referree,
356 size,
357 length,
358 tmp));
359 }
360 case JVMTI_HEAP_REFERENCE_CLASS_LOADER:
361 return std::unique_ptr<Elem>(new StringElement(referrer,
362 referree,
363 size,
364 length,
365 "classloader"));
366 case JVMTI_HEAP_REFERENCE_SIGNERS:
367 return std::unique_ptr<Elem>(new StringElement(referrer,
368 referree,
369 size,
370 length,
371 "signers"));
372 case JVMTI_HEAP_REFERENCE_PROTECTION_DOMAIN:
373 return std::unique_ptr<Elem>(new StringElement(referrer,
374 referree,
375 size,
376 length,
377 "protection-domain"));
378 case JVMTI_HEAP_REFERENCE_INTERFACE:
379 return std::unique_ptr<Elem>(new StringElement(referrer,
380 referree,
381 size,
382 length,
383 "interface"));
384 case JVMTI_HEAP_REFERENCE_STATIC_FIELD: {
385 std::string tmp = StringPrintf("array-element@%d", reference_info->array.index);
386 return std::unique_ptr<Elem>(new StringElement(referrer,
387 referree,
388 size,
389 length,
390 tmp));;
391 }
392 case JVMTI_HEAP_REFERENCE_CONSTANT_POOL:
393 return std::unique_ptr<Elem>(new StringElement(referrer,
394 referree,
395 size,
396 length,
397 "constant-pool"));
398 case JVMTI_HEAP_REFERENCE_SUPERCLASS:
399 return std::unique_ptr<Elem>(new StringElement(referrer,
400 referree,
401 size,
402 length,
403 "superclass"));
404 case JVMTI_HEAP_REFERENCE_JNI_GLOBAL:
405 return std::unique_ptr<Elem>(new StringElement(referrer,
406 referree,
407 size,
408 length,
409 "jni-global"));
410 case JVMTI_HEAP_REFERENCE_SYSTEM_CLASS:
411 return std::unique_ptr<Elem>(new StringElement(referrer,
412 referree,
413 size,
414 length,
415 "system-class"));
416 case JVMTI_HEAP_REFERENCE_MONITOR:
417 return std::unique_ptr<Elem>(new StringElement(referrer,
418 referree,
419 size,
420 length,
421 "monitor"));
422 case JVMTI_HEAP_REFERENCE_STACK_LOCAL:
Andreas Gampef10dfcd2016-12-02 14:42:33 -0800423 return std::unique_ptr<Elem>(new StackLocalElement(referrer,
424 referree,
425 size,
426 length,
427 reference_info));
Andreas Gampedce591b2016-11-17 11:23:35 -0800428 case JVMTI_HEAP_REFERENCE_JNI_LOCAL:
Andreas Gampe93c30902016-11-18 13:30:30 -0800429 return std::unique_ptr<Elem>(new JNILocalElement(referrer,
430 referree,
431 size,
432 length,
433 reference_info));
Andreas Gampedce591b2016-11-17 11:23:35 -0800434 case JVMTI_HEAP_REFERENCE_THREAD:
435 return std::unique_ptr<Elem>(new StringElement(referrer,
436 referree,
437 size,
438 length,
439 "thread"));
440 case JVMTI_HEAP_REFERENCE_OTHER:
441 return std::unique_ptr<Elem>(new StringElement(referrer,
442 referree,
443 size,
444 length,
445 "other"));
446 }
447 LOG(FATAL) << "Unknown kind";
448 UNREACHABLE();
449 }
450
Andreas Gampe216090d2016-11-15 12:33:18 -0800451 static void DumpStacks() NO_THREAD_SAFETY_ANALYSIS {
452 auto dump_function = [](art::Thread* t, void* data ATTRIBUTE_UNUSED) {
453 std::string name;
454 t->GetThreadName(name);
455 LOG(ERROR) << name;
456 art::DumpNativeStack(LOG_STREAM(ERROR), t->GetTid());
457 };
458 art::Runtime::Current()->GetThreadList()->ForEach(dump_function, nullptr);
Andreas Gampe70bfc8a2016-11-03 11:04:15 -0700459 }
460
Andreas Gampe70bfc8a2016-11-03 11:04:15 -0700461 jint counter_;
462 const jint stop_after_;
463 const jint follow_set_;
Andreas Gampedce591b2016-11-17 11:23:35 -0800464
465 std::vector<std::unique_ptr<Elem>> lines_;
Andreas Gampe70bfc8a2016-11-03 11:04:15 -0700466 };
467
Andreas Gampe8df06922016-11-16 10:58:11 -0800468 jit::ScopedJitSuspend sjs; // Wait to avoid JIT influence (e.g., JNI globals).
469
Andreas Gampe70bfc8a2016-11-03 11:04:15 -0700470 // If jniRef isn't null, add a local and a global ref.
471 ScopedLocalRef<jobject> jni_local_ref(env, nullptr);
472 jobject jni_global_ref = nullptr;
473 if (jniRef != nullptr) {
474 jni_local_ref.reset(env->NewLocalRef(jniRef));
475 jni_global_ref = env->NewGlobalRef(jniRef);
476 }
477
478 PrintIterationConfig config(stop_after, follow_set);
479 Run(heap_filter, klass_filter, initial_object, &config);
480
Andreas Gampedce591b2016-11-17 11:23:35 -0800481 std::vector<std::string> lines = config.GetLines();
Andreas Gampe70bfc8a2016-11-03 11:04:15 -0700482 jobjectArray ret = CreateObjectArray(env,
483 static_cast<jint>(lines.size()),
484 "java/lang/String",
485 [&](jint i) {
486 return env->NewStringUTF(lines[i].c_str());
487 });
488
489 if (jni_global_ref != nullptr) {
490 env->DeleteGlobalRef(jni_global_ref);
491 }
492
493 return ret;
494}
495
Andreas Gampe8da6d032016-10-31 19:31:03 -0700496// Don't do anything
497jint OnLoad(JavaVM* vm,
498 char* options ATTRIBUTE_UNUSED,
499 void* reserved ATTRIBUTE_UNUSED) {
500 if (vm->GetEnv(reinterpret_cast<void**>(&jvmti_env), JVMTI_VERSION_1_0)) {
501 printf("Unable to get jvmti env!\n");
502 return 1;
503 }
Alex Lighte6574242016-08-17 09:56:24 -0700504 SetAllCapabilities(jvmti_env);
Andreas Gampe8da6d032016-10-31 19:31:03 -0700505 return 0;
506}
507
Andreas Gampe8da6d032016-10-31 19:31:03 -0700508} // namespace Test913Heaps
509} // namespace art