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