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