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