blob: 67599192cfbc96f92f79b571c7f16e46d6baa322 [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
Andreas Gampe70bfc8a2016-11-03 11:04:15 -070017#include <inttypes.h>
Andreas Gampe8da6d032016-10-31 19:31:03 -070018#include <stdio.h>
19#include <string.h>
20
Andreas Gampe70bfc8a2016-11-03 11:04:15 -070021#include <vector>
22
Andreas Gampe46ee31b2016-12-14 10:11:49 -080023#include "android-base/stringprintf.h"
24
Andreas Gampe70bfc8a2016-11-03 11:04:15 -070025#include "base/logging.h"
Andreas Gampe8da6d032016-10-31 19:31:03 -070026#include "base/macros.h"
Andreas Gampe5d139fc2016-11-09 22:54:25 -080027#include "jit/jit.h"
Andreas Gampe8da6d032016-10-31 19:31:03 -070028#include "jni.h"
Andreas Gampe216090d2016-11-15 12:33:18 -080029#include "native_stack_dump.h"
Andreas Gampe8da6d032016-10-31 19:31:03 -070030#include "openjdkjvmti/jvmti.h"
Andreas Gampe5d139fc2016-11-09 22:54:25 -080031#include "runtime.h"
32#include "thread-inl.h"
Andreas Gampe216090d2016-11-15 12:33:18 -080033#include "thread_list.h"
Alex Lighte6574242016-08-17 09:56:24 -070034
Andreas Gampe70bfc8a2016-11-03 11:04:15 -070035#include "ti-agent/common_helper.h"
Andreas Gampe8da6d032016-10-31 19:31:03 -070036#include "ti-agent/common_load.h"
37
38namespace art {
39namespace Test913Heaps {
40
Andreas Gampe46ee31b2016-12-14 10:11:49 -080041using android::base::StringPrintf;
42
Andreas Gampe8da6d032016-10-31 19:31:03 -070043extern "C" JNIEXPORT void JNICALL Java_Main_forceGarbageCollection(JNIEnv* env ATTRIBUTE_UNUSED,
44 jclass klass ATTRIBUTE_UNUSED) {
45 jvmtiError ret = jvmti_env->ForceGarbageCollection();
46 if (ret != JVMTI_ERROR_NONE) {
47 char* err;
48 jvmti_env->GetErrorName(ret, &err);
49 printf("Error forcing a garbage collection: %s\n", err);
Alex Light41960712017-01-06 14:44:23 -080050 jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(err));
Andreas Gampe8da6d032016-10-31 19:31:03 -070051 }
52}
53
Andreas Gampe70bfc8a2016-11-03 11:04:15 -070054class IterationConfig {
55 public:
56 IterationConfig() {}
57 virtual ~IterationConfig() {}
58
59 virtual jint Handle(jvmtiHeapReferenceKind reference_kind,
60 const jvmtiHeapReferenceInfo* reference_info,
61 jlong class_tag,
62 jlong referrer_class_tag,
63 jlong size,
64 jlong* tag_ptr,
65 jlong* referrer_tag_ptr,
66 jint length,
67 void* user_data) = 0;
68};
69
70static jint JNICALL HeapReferenceCallback(jvmtiHeapReferenceKind reference_kind,
71 const jvmtiHeapReferenceInfo* reference_info,
72 jlong class_tag,
73 jlong referrer_class_tag,
74 jlong size,
75 jlong* tag_ptr,
76 jlong* referrer_tag_ptr,
77 jint length,
78 void* user_data) {
79 IterationConfig* config = reinterpret_cast<IterationConfig*>(user_data);
80 return config->Handle(reference_kind,
81 reference_info,
82 class_tag,
83 referrer_class_tag,
84 size,
85 tag_ptr,
86 referrer_tag_ptr,
87 length,
88 user_data);
89}
90
91static bool Run(jint heap_filter,
92 jclass klass_filter,
93 jobject initial_object,
94 IterationConfig* config) {
95 jvmtiHeapCallbacks callbacks;
96 memset(&callbacks, 0, sizeof(jvmtiHeapCallbacks));
97 callbacks.heap_reference_callback = HeapReferenceCallback;
98
99 jvmtiError ret = jvmti_env->FollowReferences(heap_filter,
100 klass_filter,
101 initial_object,
102 &callbacks,
103 config);
104 if (ret != JVMTI_ERROR_NONE) {
105 char* err;
106 jvmti_env->GetErrorName(ret, &err);
107 printf("Failure running FollowReferences: %s\n", err);
Alex Light41960712017-01-06 14:44:23 -0800108 jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(err));
Andreas Gampe70bfc8a2016-11-03 11:04:15 -0700109 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.
Nicolas Geoffrayf9bf2502016-12-14 14:59:04 +0000186 if ((sizeof(void*) == 4 && size == 172) || (sizeof(void*) == 8 && size == 224)) {
Andreas Gampe70bfc8a2016-11-03 11:04:15 -0700187 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} // namespace Test913Heaps
497} // namespace art