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