1 /*
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 <inttypes.h>
18
19 #include <cstdio>
20 #include <cstring>
21 #include <iostream>
22 #include <map>
23 #include <sstream>
24 #include <vector>
25
26 #include "android-base/logging.h"
27 #include "android-base/macros.h"
28 #include "android-base/stringprintf.h"
29
30 #include "jni.h"
31 #include "jvmti.h"
32
33 // Test infrastructure
34 #include "jni_helper.h"
35 #include "jvmti_helper.h"
36 #include "test_env.h"
37 #include "ti_utf.h"
38
39 namespace art {
40 namespace Test913Heaps {
41
42 using android::base::StringPrintf;
43
44 #define UNREACHABLE __builtin_unreachable
45
46 // The tag value used on the Java side to tag the current thread.
47 static constexpr jlong kThreadTag = 3000;
48 static constexpr const char* kThreadReferree = "3000@0";
49
Java_art_Test913_forceGarbageCollection(JNIEnv * env,jclass klass ATTRIBUTE_UNUSED)50 extern "C" JNIEXPORT void JNICALL Java_art_Test913_forceGarbageCollection(
51 JNIEnv* env, jclass klass ATTRIBUTE_UNUSED) {
52 jvmtiError ret = jvmti_env->ForceGarbageCollection();
53 JvmtiErrorToException(env, jvmti_env, ret);
54 }
55
56 // Collect sizes of objects (classes) ahead of time, to be able to normalize.
57 struct ClassData {
58 jlong size; // Size as reported by GetObjectSize.
59 jlong serial; // Computed serial that should be printed instead of the size.
60 };
61
62 // Stores a map from tags to ClassData.
63 static std::map<jlong, ClassData> sClassData;
64 static size_t sClassDataSerial = 0;
65 // Large enough number that a collision with a test object is unlikely.
66 static constexpr jlong kClassDataSerialBase = 123456780000;
67
68 // Register a class (or general object) in the class-data map. The serial number is determined by
69 // the order of calls to this function (so stable Java code leads to stable numbering).
Java_art_Test913_registerClass(JNIEnv * env,jclass klass ATTRIBUTE_UNUSED,jlong tag,jobject obj)70 extern "C" JNIEXPORT void JNICALL Java_art_Test913_registerClass(
71 JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jlong tag, jobject obj) {
72 ClassData data;
73 if (JvmtiErrorToException(env, jvmti_env, jvmti_env->GetObjectSize(obj, &data.size))) {
74 return;
75 }
76 data.serial = kClassDataSerialBase + sClassDataSerial++;
77 // Remove old element, if it exists.
78 auto old = sClassData.find(tag);
79 if (old != sClassData.end()) {
80 sClassData.erase(old);
81 }
82 // Now insert the new mapping.
83 sClassData.insert(std::pair<jlong, ClassData>(tag, data));
84 }
85
86 class IterationConfig {
87 public:
IterationConfig()88 IterationConfig() {}
~IterationConfig()89 virtual ~IterationConfig() {}
90
91 virtual jint Handle(jvmtiHeapReferenceKind reference_kind,
92 const jvmtiHeapReferenceInfo* reference_info,
93 jlong class_tag,
94 jlong referrer_class_tag,
95 jlong size,
96 jlong* tag_ptr,
97 jlong* referrer_tag_ptr,
98 jint length,
99 void* user_data) = 0;
100 };
101
HeapReferenceCallback(jvmtiHeapReferenceKind reference_kind,const jvmtiHeapReferenceInfo * reference_info,jlong class_tag,jlong referrer_class_tag,jlong size,jlong * tag_ptr,jlong * referrer_tag_ptr,jint length,void * user_data)102 static jint JNICALL HeapReferenceCallback(jvmtiHeapReferenceKind reference_kind,
103 const jvmtiHeapReferenceInfo* reference_info,
104 jlong class_tag,
105 jlong referrer_class_tag,
106 jlong size,
107 jlong* tag_ptr,
108 jlong* referrer_tag_ptr,
109 jint length,
110 void* user_data) {
111 IterationConfig* config = reinterpret_cast<IterationConfig*>(user_data);
112 return config->Handle(reference_kind,
113 reference_info,
114 class_tag,
115 referrer_class_tag,
116 size,
117 tag_ptr,
118 referrer_tag_ptr,
119 length,
120 user_data);
121 }
122
Run(JNIEnv * env,jint heap_filter,jclass klass_filter,jobject initial_object,IterationConfig * config)123 static bool Run(JNIEnv* env,
124 jint heap_filter,
125 jclass klass_filter,
126 jobject initial_object,
127 IterationConfig* config) {
128 jvmtiHeapCallbacks callbacks;
129 memset(&callbacks, 0, sizeof(jvmtiHeapCallbacks));
130 callbacks.heap_reference_callback = HeapReferenceCallback;
131
132 jvmtiError ret = jvmti_env->FollowReferences(heap_filter,
133 klass_filter,
134 initial_object,
135 &callbacks,
136 config);
137 return !JvmtiErrorToException(env, jvmti_env, ret);
138 }
139
Java_art_Test913_followReferences(JNIEnv * env,jclass klass ATTRIBUTE_UNUSED,jint heap_filter,jclass klass_filter,jobject initial_object,jint stop_after,jint follow_set,jobject jniRef)140 extern "C" JNIEXPORT jobjectArray JNICALL Java_art_Test913_followReferences(
141 JNIEnv* env,
142 jclass klass ATTRIBUTE_UNUSED,
143 jint heap_filter,
144 jclass klass_filter,
145 jobject initial_object,
146 jint stop_after,
147 jint follow_set,
148 jobject jniRef) {
149 class PrintIterationConfig final : public IterationConfig {
150 public:
151 PrintIterationConfig(jint _stop_after, jint _follow_set)
152 : counter_(0),
153 stop_after_(_stop_after),
154 follow_set_(_follow_set) {
155 }
156
157 jint Handle(jvmtiHeapReferenceKind reference_kind,
158 const jvmtiHeapReferenceInfo* reference_info,
159 jlong class_tag,
160 jlong referrer_class_tag,
161 jlong size,
162 jlong* tag_ptr,
163 jlong* referrer_tag_ptr,
164 jint length,
165 void* user_data ATTRIBUTE_UNUSED) override {
166 jlong tag = *tag_ptr;
167
168 // Ignore any jni-global roots with untagged classes. These can be from the environment,
169 // or the JIT.
170 if (reference_kind == JVMTI_HEAP_REFERENCE_JNI_GLOBAL && class_tag == 0) {
171 return 0;
172 }
173 // Ignore HEAP_REFERENCE_OTHER roots because these are vm-internal roots and can vary
174 // depending on the configuration of the runtime (notably having trampoline tracing will add a
175 // lot of these).
176 if (reference_kind == JVMTI_HEAP_REFERENCE_OTHER) {
177 return 0;
178 }
179 // Ignore classes (1000 <= tag < 3000) for thread objects. These can be held by the JIT.
180 if (reference_kind == JVMTI_HEAP_REFERENCE_THREAD && class_tag == 0 &&
181 (1000 <= *tag_ptr && *tag_ptr < kThreadTag)) {
182 return 0;
183 }
184 // Ignore stack-locals of untagged threads. That is the environment.
185 if (reference_kind == JVMTI_HEAP_REFERENCE_STACK_LOCAL &&
186 reference_info->stack_local.thread_tag != kThreadTag) {
187 return 0;
188 }
189 // Ignore array elements with an untagged source. These are from the environment.
190 if (reference_kind == JVMTI_HEAP_REFERENCE_ARRAY_ELEMENT && *referrer_tag_ptr == 0) {
191 return 0;
192 }
193
194 // Only check tagged objects.
195 if (tag == 0) {
196 return JVMTI_VISIT_OBJECTS;
197 }
198
199 Print(reference_kind,
200 reference_info,
201 class_tag,
202 referrer_class_tag,
203 size,
204 tag_ptr,
205 referrer_tag_ptr,
206 length);
207
208 counter_++;
209 if (counter_ == stop_after_) {
210 return JVMTI_VISIT_ABORT;
211 }
212
213 if (tag > 0 && tag < 32) {
214 bool should_visit_references = (follow_set_ & (1 << static_cast<int32_t>(tag))) != 0;
215 return should_visit_references ? JVMTI_VISIT_OBJECTS : 0;
216 }
217
218 return JVMTI_VISIT_OBJECTS;
219 }
220
221 void Print(jvmtiHeapReferenceKind reference_kind,
222 const jvmtiHeapReferenceInfo* reference_info,
223 jlong class_tag,
224 jlong referrer_class_tag,
225 jlong size,
226 jlong* tag_ptr,
227 jlong* referrer_tag_ptr,
228 jint length) {
229 std::string referrer_str;
230 if (referrer_tag_ptr == nullptr) {
231 referrer_str = "root@root";
232 } else {
233 referrer_str = StringPrintf("%" PRId64 "@%" PRId64, *referrer_tag_ptr, referrer_class_tag);
234 }
235
236 jlong adapted_size = size;
237 if (*tag_ptr != 0) {
238 // This is a class or interface, the size of which will be dependent on the architecture.
239 // Do not print the size, but detect known values and "normalize" for the golden file.
240 auto it = sClassData.find(*tag_ptr);
241 if (it != sClassData.end()) {
242 const ClassData& class_data = it->second;
243 if (class_data.size == size) {
244 adapted_size = class_data.serial;
245 } else {
246 adapted_size = 0xDEADDEAD;
247 }
248 }
249 }
250
251 std::string referree_str = StringPrintf("%" PRId64 "@%" PRId64, *tag_ptr, class_tag);
252
253 lines_.push_back(CreateElem(referrer_str,
254 referree_str,
255 reference_kind,
256 reference_info,
257 adapted_size,
258 length));
259 }
260
261 std::vector<std::string> GetLines() const {
262 std::vector<std::string> ret;
263 for (const std::unique_ptr<Elem>& e : lines_) {
264 ret.push_back(e->Print());
265 }
266 return ret;
267 }
268
269 private:
270 // We need to postpone some printing, as required functions are not callback-safe.
271 class Elem {
272 public:
273 Elem(const std::string& referrer, const std::string& referree, jlong size, jint length)
274 : referrer_(referrer), referree_(referree), size_(size), length_(length) {}
275 virtual ~Elem() {}
276
277 std::string Print() const {
278 return StringPrintf("%s --(%s)--> %s [size=%" PRId64 ", length=%d]",
279 referrer_.c_str(),
280 PrintArrowType().c_str(),
281 referree_.c_str(),
282 size_,
283 length_);
284 }
285
286 protected:
287 virtual std::string PrintArrowType() const = 0;
288
289 private:
290 std::string referrer_;
291 std::string referree_;
292 jlong size_;
293 jint length_;
294 };
295
296 class JNILocalElement : public Elem {
297 public:
298 JNILocalElement(const std::string& referrer,
299 const std::string& referree,
300 jlong size,
301 jint length,
302 const jvmtiHeapReferenceInfo* reference_info)
303 : Elem(referrer, referree, size, length) {
304 memcpy(&info_, reference_info, sizeof(jvmtiHeapReferenceInfo));
305 }
306
307 protected:
308 std::string PrintArrowType() const override {
309 char* name = nullptr;
310 if (info_.jni_local.method != nullptr) {
311 jvmti_env->GetMethodName(info_.jni_local.method, &name, nullptr, nullptr);
312 }
313 // Normalize the thread id, as this depends on the number of other threads
314 // and which thread is running the test. Should be:
315 // jlong thread_id = info_.jni_local.thread_id;
316 // TODO: A pre-pass before the test should be able fetch this number, so it can
317 // be compared explicitly.
318 jlong thread_id = 1;
319 std::string ret = StringPrintf("jni-local[id=%" PRId64 ",tag=%" PRId64 ",depth=%d,"
320 "method=%s]",
321 thread_id,
322 info_.jni_local.thread_tag,
323 info_.jni_local.depth,
324 name == nullptr ? "<null>" : name);
325 if (name != nullptr) {
326 jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(name));
327 }
328
329 return ret;
330 }
331
332 private:
333 const std::string string_;
334 jvmtiHeapReferenceInfo info_;
335 };
336
337 class StackLocalElement : public Elem {
338 public:
339 StackLocalElement(const std::string& referrer,
340 const std::string& referree,
341 jlong size,
342 jint length,
343 const jvmtiHeapReferenceInfo* reference_info)
344 : Elem(referrer, referree, size, length) {
345 memcpy(&info_, reference_info, sizeof(jvmtiHeapReferenceInfo));
346
347 // Debug code. Try to figure out where bad depth is coming from.
348 if (reference_info->stack_local.depth == 6) {
349 LOG(FATAL) << "Unexpected depth of 6";
350 }
351 }
352
353 protected:
354 std::string PrintArrowType() const override {
355 char* name = nullptr;
356 if (info_.stack_local.method != nullptr) {
357 jvmti_env->GetMethodName(info_.stack_local.method, &name, nullptr, nullptr);
358 }
359 // Normalize the thread id, as this depends on the number of other threads
360 // and which thread is running the test. Should be:
361 // jlong thread_id = info_.stack_local.thread_id;
362 // TODO: A pre-pass before the test should be able fetch this number, so it can
363 // be compared explicitly.
364 jlong thread_id = 1;
365 std::string ret = StringPrintf("stack-local[id=%" PRId64 ",tag=%" PRId64 ",depth=%d,"
366 "method=%s,vreg=%d,location=% " PRId64 "]",
367 thread_id,
368 info_.stack_local.thread_tag,
369 info_.stack_local.depth,
370 name == nullptr ? "<null>" : name,
371 info_.stack_local.slot,
372 info_.stack_local.location);
373 if (name != nullptr) {
374 jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(name));
375 }
376
377 return ret;
378 }
379
380 private:
381 const std::string string_;
382 jvmtiHeapReferenceInfo info_;
383 };
384
385 // For simple or unimplemented cases.
386 class StringElement : public Elem {
387 public:
388 StringElement(const std::string& referrer,
389 const std::string& referree,
390 jlong size,
391 jint length,
392 const std::string& string)
393 : Elem(referrer, referree, size, length), string_(string) {}
394
395 protected:
396 std::string PrintArrowType() const override {
397 return string_;
398 }
399
400 private:
401 const std::string string_;
402 };
403
404 static std::unique_ptr<Elem> CreateElem(const std::string& referrer,
405 const std::string& referree,
406 jvmtiHeapReferenceKind reference_kind,
407 const jvmtiHeapReferenceInfo* reference_info,
408 jlong size,
409 jint length) {
410 switch (reference_kind) {
411 case JVMTI_HEAP_REFERENCE_CLASS:
412 return std::unique_ptr<Elem>(new StringElement(referrer,
413 referree,
414 size,
415 length,
416 "class"));
417 case JVMTI_HEAP_REFERENCE_FIELD: {
418 std::string tmp = StringPrintf("field@%d", reference_info->field.index);
419 return std::unique_ptr<Elem>(new StringElement(referrer,
420 referree,
421 size,
422 length,
423 tmp));
424 }
425 case JVMTI_HEAP_REFERENCE_ARRAY_ELEMENT: {
426 jint index = reference_info->array.index;
427 // Normalize if it's "0@0" -> "3000@1".
428 // TODO: A pre-pass could probably give us this index to check explicitly.
429 if (referrer == "0@0" && referree == kThreadReferree) {
430 index = 0;
431 }
432 std::string tmp = StringPrintf("array-element@%d", index);
433 return std::unique_ptr<Elem>(new StringElement(referrer,
434 referree,
435 size,
436 length,
437 tmp));
438 }
439 case JVMTI_HEAP_REFERENCE_CLASS_LOADER:
440 return std::unique_ptr<Elem>(new StringElement(referrer,
441 referree,
442 size,
443 length,
444 "classloader"));
445 case JVMTI_HEAP_REFERENCE_SIGNERS:
446 return std::unique_ptr<Elem>(new StringElement(referrer,
447 referree,
448 size,
449 length,
450 "signers"));
451 case JVMTI_HEAP_REFERENCE_PROTECTION_DOMAIN:
452 return std::unique_ptr<Elem>(new StringElement(referrer,
453 referree,
454 size,
455 length,
456 "protection-domain"));
457 case JVMTI_HEAP_REFERENCE_INTERFACE:
458 return std::unique_ptr<Elem>(new StringElement(referrer,
459 referree,
460 size,
461 length,
462 "interface"));
463 case JVMTI_HEAP_REFERENCE_STATIC_FIELD: {
464 std::string tmp = StringPrintf("array-element@%d", reference_info->array.index);
465 return std::unique_ptr<Elem>(new StringElement(referrer,
466 referree,
467 size,
468 length,
469 tmp));;
470 }
471 case JVMTI_HEAP_REFERENCE_CONSTANT_POOL:
472 return std::unique_ptr<Elem>(new StringElement(referrer,
473 referree,
474 size,
475 length,
476 "constant-pool"));
477 case JVMTI_HEAP_REFERENCE_SUPERCLASS:
478 return std::unique_ptr<Elem>(new StringElement(referrer,
479 referree,
480 size,
481 length,
482 "superclass"));
483 case JVMTI_HEAP_REFERENCE_JNI_GLOBAL:
484 return std::unique_ptr<Elem>(new StringElement(referrer,
485 referree,
486 size,
487 length,
488 "jni-global"));
489 case JVMTI_HEAP_REFERENCE_SYSTEM_CLASS:
490 return std::unique_ptr<Elem>(new StringElement(referrer,
491 referree,
492 size,
493 length,
494 "system-class"));
495 case JVMTI_HEAP_REFERENCE_MONITOR:
496 return std::unique_ptr<Elem>(new StringElement(referrer,
497 referree,
498 size,
499 length,
500 "monitor"));
501 case JVMTI_HEAP_REFERENCE_STACK_LOCAL:
502 return std::unique_ptr<Elem>(new StackLocalElement(referrer,
503 referree,
504 size,
505 length,
506 reference_info));
507 case JVMTI_HEAP_REFERENCE_JNI_LOCAL:
508 return std::unique_ptr<Elem>(new JNILocalElement(referrer,
509 referree,
510 size,
511 length,
512 reference_info));
513 case JVMTI_HEAP_REFERENCE_THREAD:
514 return std::unique_ptr<Elem>(new StringElement(referrer,
515 referree,
516 size,
517 length,
518 "thread"));
519 case JVMTI_HEAP_REFERENCE_OTHER:
520 return std::unique_ptr<Elem>(new StringElement(referrer,
521 referree,
522 size,
523 length,
524 "other"));
525 }
526 LOG(FATAL) << "Unknown kind";
527 UNREACHABLE();
528 }
529
530 jint counter_;
531 const jint stop_after_;
532 const jint follow_set_;
533
534 std::vector<std::unique_ptr<Elem>> lines_;
535 };
536
537 // If jniRef isn't null, add a local and a global ref.
538 ScopedLocalRef<jobject> jni_local_ref(env, nullptr);
539 jobject jni_global_ref = nullptr;
540 if (jniRef != nullptr) {
541 jni_local_ref.reset(env->NewLocalRef(jniRef));
542 jni_global_ref = env->NewGlobalRef(jniRef);
543 }
544
545 PrintIterationConfig config(stop_after, follow_set);
546 if (!Run(env, heap_filter, klass_filter, initial_object, &config)) {
547 return nullptr;
548 }
549
550 std::vector<std::string> lines = config.GetLines();
551 jobjectArray ret = CreateObjectArray(env,
552 static_cast<jint>(lines.size()),
553 "java/lang/String",
554 [&](jint i) {
555 return env->NewStringUTF(lines[i].c_str());
556 });
557
558 if (jni_global_ref != nullptr) {
559 env->DeleteGlobalRef(jni_global_ref);
560 }
561
562 return ret;
563 }
564
Java_art_Test913_followReferencesString(JNIEnv * env,jclass klass ATTRIBUTE_UNUSED,jobject initial_object)565 extern "C" JNIEXPORT jobjectArray JNICALL Java_art_Test913_followReferencesString(
566 JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jobject initial_object) {
567 struct FindStringCallbacks {
568 static jint JNICALL FollowReferencesCallback(
569 jvmtiHeapReferenceKind reference_kind ATTRIBUTE_UNUSED,
570 const jvmtiHeapReferenceInfo* reference_info ATTRIBUTE_UNUSED,
571 jlong class_tag ATTRIBUTE_UNUSED,
572 jlong referrer_class_tag ATTRIBUTE_UNUSED,
573 jlong size ATTRIBUTE_UNUSED,
574 jlong* tag_ptr ATTRIBUTE_UNUSED,
575 jlong* referrer_tag_ptr ATTRIBUTE_UNUSED,
576 jint length ATTRIBUTE_UNUSED,
577 void* user_data ATTRIBUTE_UNUSED) {
578 return JVMTI_VISIT_OBJECTS; // Continue visiting.
579 }
580
581 static jint JNICALL StringValueCallback(jlong class_tag,
582 jlong size,
583 jlong* tag_ptr,
584 const jchar* value,
585 jint value_length,
586 void* user_data) {
587 FindStringCallbacks* p = reinterpret_cast<FindStringCallbacks*>(user_data);
588 if (*tag_ptr != 0) {
589 size_t utf_byte_count = ti::CountUtf8Bytes(value, value_length);
590 std::unique_ptr<char[]> mod_utf(new char[utf_byte_count + 1]);
591 memset(mod_utf.get(), 0, utf_byte_count + 1);
592 ti::ConvertUtf16ToModifiedUtf8(mod_utf.get(), utf_byte_count, value, value_length);
593 p->data.push_back(android::base::StringPrintf("%" PRId64 "@%" PRId64 " (%" PRId64 ", '%s')",
594 *tag_ptr,
595 class_tag,
596 size,
597 mod_utf.get()));
598 // Update the tag to test whether that works.
599 *tag_ptr = *tag_ptr + 1;
600 }
601 return 0;
602 }
603
604 std::vector<std::string> data;
605 };
606
607 jvmtiHeapCallbacks callbacks;
608 memset(&callbacks, 0, sizeof(jvmtiHeapCallbacks));
609 callbacks.heap_reference_callback = FindStringCallbacks::FollowReferencesCallback;
610 callbacks.string_primitive_value_callback = FindStringCallbacks::StringValueCallback;
611
612 FindStringCallbacks fsc;
613 jvmtiError ret = jvmti_env->FollowReferences(0, nullptr, initial_object, &callbacks, &fsc);
614 if (JvmtiErrorToException(env, jvmti_env, ret)) {
615 return nullptr;
616 }
617
618 jobjectArray retArray = CreateObjectArray(env,
619 static_cast<jint>(fsc.data.size()),
620 "java/lang/String",
621 [&](jint i) {
622 return env->NewStringUTF(fsc.data[i].c_str());
623 });
624 return retArray;
625 }
626
627
Java_art_Test913_followReferencesPrimitiveArray(JNIEnv * env,jclass klass ATTRIBUTE_UNUSED,jobject initial_object)628 extern "C" JNIEXPORT jstring JNICALL Java_art_Test913_followReferencesPrimitiveArray(
629 JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jobject initial_object) {
630 struct FindArrayCallbacks {
631 static jint JNICALL FollowReferencesCallback(
632 jvmtiHeapReferenceKind reference_kind ATTRIBUTE_UNUSED,
633 const jvmtiHeapReferenceInfo* reference_info ATTRIBUTE_UNUSED,
634 jlong class_tag ATTRIBUTE_UNUSED,
635 jlong referrer_class_tag ATTRIBUTE_UNUSED,
636 jlong size ATTRIBUTE_UNUSED,
637 jlong* tag_ptr ATTRIBUTE_UNUSED,
638 jlong* referrer_tag_ptr ATTRIBUTE_UNUSED,
639 jint length ATTRIBUTE_UNUSED,
640 void* user_data ATTRIBUTE_UNUSED) {
641 return JVMTI_VISIT_OBJECTS; // Continue visiting.
642 }
643
644 static jint JNICALL ArrayValueCallback(jlong class_tag,
645 jlong size,
646 jlong* tag_ptr,
647 jint element_count,
648 jvmtiPrimitiveType element_type,
649 const void* elements,
650 void* user_data) {
651 FindArrayCallbacks* p = reinterpret_cast<FindArrayCallbacks*>(user_data);
652 // The thread object may be reachable from the starting value because of setup in the
653 // framework (when this test runs as part of CTS). Ignore, we're not testing the thread
654 // here.)
655 if (*tag_ptr != 0 && *tag_ptr != kThreadTag) {
656 std::ostringstream oss;
657 oss << *tag_ptr
658 << '@'
659 << class_tag
660 << " ("
661 << size
662 << ", "
663 << element_count
664 << "x"
665 << static_cast<char>(element_type)
666 << " '";
667 size_t element_size;
668 switch (element_type) {
669 case JVMTI_PRIMITIVE_TYPE_BOOLEAN:
670 case JVMTI_PRIMITIVE_TYPE_BYTE:
671 element_size = 1;
672 break;
673 case JVMTI_PRIMITIVE_TYPE_CHAR:
674 case JVMTI_PRIMITIVE_TYPE_SHORT:
675 element_size = 2;
676 break;
677 case JVMTI_PRIMITIVE_TYPE_INT:
678 case JVMTI_PRIMITIVE_TYPE_FLOAT:
679 element_size = 4;
680 break;
681 case JVMTI_PRIMITIVE_TYPE_LONG:
682 case JVMTI_PRIMITIVE_TYPE_DOUBLE:
683 element_size = 8;
684 break;
685 default:
686 LOG(FATAL) << "Unknown type " << static_cast<size_t>(element_type);
687 UNREACHABLE();
688 }
689 const uint8_t* data = reinterpret_cast<const uint8_t*>(elements);
690 for (size_t i = 0; i != element_size * element_count; ++i) {
691 oss << android::base::StringPrintf("%02x", data[i]);
692 }
693 oss << "')";
694
695 if (!p->data.empty()) {
696 p->data += "\n";
697 }
698 p->data += oss.str();
699 // Update the tag to test whether that works.
700 *tag_ptr = *tag_ptr + 1;
701 }
702 return 0;
703 }
704
705 std::string data;
706 };
707
708 jvmtiHeapCallbacks callbacks;
709 memset(&callbacks, 0, sizeof(jvmtiHeapCallbacks));
710 callbacks.heap_reference_callback = FindArrayCallbacks::FollowReferencesCallback;
711 callbacks.array_primitive_value_callback = FindArrayCallbacks::ArrayValueCallback;
712
713 FindArrayCallbacks fac;
714 jvmtiError ret = jvmti_env->FollowReferences(0, nullptr, initial_object, &callbacks, &fac);
715 if (JvmtiErrorToException(env, jvmti_env, ret)) {
716 return nullptr;
717 }
718 return env->NewStringUTF(fac.data.c_str());
719 }
720
GetPrimitiveTypeName(jvmtiPrimitiveType type)721 static constexpr const char* GetPrimitiveTypeName(jvmtiPrimitiveType type) {
722 switch (type) {
723 case JVMTI_PRIMITIVE_TYPE_BOOLEAN:
724 return "boolean";
725 case JVMTI_PRIMITIVE_TYPE_BYTE:
726 return "byte";
727 case JVMTI_PRIMITIVE_TYPE_CHAR:
728 return "char";
729 case JVMTI_PRIMITIVE_TYPE_SHORT:
730 return "short";
731 case JVMTI_PRIMITIVE_TYPE_INT:
732 return "int";
733 case JVMTI_PRIMITIVE_TYPE_FLOAT:
734 return "float";
735 case JVMTI_PRIMITIVE_TYPE_LONG:
736 return "long";
737 case JVMTI_PRIMITIVE_TYPE_DOUBLE:
738 return "double";
739 }
740 LOG(FATAL) << "Unknown type " << static_cast<size_t>(type);
741 UNREACHABLE();
742 }
743
Java_art_Test913_followReferencesPrimitiveFields(JNIEnv * env,jclass klass ATTRIBUTE_UNUSED,jobject initial_object)744 extern "C" JNIEXPORT jstring JNICALL Java_art_Test913_followReferencesPrimitiveFields(
745 JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jobject initial_object) {
746 struct FindFieldCallbacks {
747 static jint JNICALL FollowReferencesCallback(
748 jvmtiHeapReferenceKind reference_kind ATTRIBUTE_UNUSED,
749 const jvmtiHeapReferenceInfo* reference_info ATTRIBUTE_UNUSED,
750 jlong class_tag ATTRIBUTE_UNUSED,
751 jlong referrer_class_tag ATTRIBUTE_UNUSED,
752 jlong size ATTRIBUTE_UNUSED,
753 jlong* tag_ptr ATTRIBUTE_UNUSED,
754 jlong* referrer_tag_ptr ATTRIBUTE_UNUSED,
755 jint length ATTRIBUTE_UNUSED,
756 void* user_data ATTRIBUTE_UNUSED) {
757 return JVMTI_VISIT_OBJECTS; // Continue visiting.
758 }
759
760 static jint JNICALL PrimitiveFieldValueCallback(jvmtiHeapReferenceKind kind,
761 const jvmtiHeapReferenceInfo* info,
762 jlong class_tag,
763 jlong* tag_ptr,
764 jvalue value,
765 jvmtiPrimitiveType value_type,
766 void* user_data) {
767 FindFieldCallbacks* p = reinterpret_cast<FindFieldCallbacks*>(user_data);
768 // The thread object may be reachable from the starting value because of setup in the
769 // framework (when this test runs as part of CTS). Ignore, we're not testing the thread
770 // here.)
771 if (*tag_ptr != 0 && *tag_ptr != kThreadTag) {
772 std::ostringstream oss;
773 oss << *tag_ptr
774 << '@'
775 << class_tag
776 << " ("
777 << (kind == JVMTI_HEAP_REFERENCE_FIELD ? "instance, " : "static, ")
778 << GetPrimitiveTypeName(value_type)
779 << ", index="
780 << info->field.index
781 << ") ";
782 // Be lazy, always print eight bytes.
783 static_assert(sizeof(jvalue) == sizeof(uint64_t), "Unexpected jvalue size");
784 uint64_t val;
785 memcpy(&val, &value, sizeof(uint64_t)); // To avoid undefined behavior.
786 oss << android::base::StringPrintf("%016" PRIx64, val);
787
788 if (!p->data.empty()) {
789 p->data += "\n";
790 }
791 p->data += oss.str();
792 // Update the tag to test whether that works.
793 *tag_ptr = *tag_ptr + 1;
794 }
795 return 0;
796 }
797
798 std::string data;
799 };
800
801 jvmtiHeapCallbacks callbacks;
802 memset(&callbacks, 0, sizeof(jvmtiHeapCallbacks));
803 callbacks.heap_reference_callback = FindFieldCallbacks::FollowReferencesCallback;
804 callbacks.primitive_field_callback = FindFieldCallbacks::PrimitiveFieldValueCallback;
805
806 FindFieldCallbacks ffc;
807 jvmtiError ret = jvmti_env->FollowReferences(0, nullptr, initial_object, &callbacks, &ffc);
808 if (JvmtiErrorToException(env, jvmti_env, ret)) {
809 return nullptr;
810 }
811 return env->NewStringUTF(ffc.data.c_str());
812 }
813
814 // This is copied from test 908. Consider moving this to the main shim.
815
816 static size_t starts = 0;
817 static size_t finishes = 0;
818
GarbageCollectionFinish(jvmtiEnv * ti_env ATTRIBUTE_UNUSED)819 static void JNICALL GarbageCollectionFinish(jvmtiEnv* ti_env ATTRIBUTE_UNUSED) {
820 finishes++;
821 }
822
GarbageCollectionStart(jvmtiEnv * ti_env ATTRIBUTE_UNUSED)823 static void JNICALL GarbageCollectionStart(jvmtiEnv* ti_env ATTRIBUTE_UNUSED) {
824 starts++;
825 }
826
Java_art_Test913_setupGcCallback(JNIEnv * env,jclass klass ATTRIBUTE_UNUSED)827 extern "C" JNIEXPORT void JNICALL Java_art_Test913_setupGcCallback(
828 JNIEnv* env, jclass klass ATTRIBUTE_UNUSED) {
829 jvmtiEventCallbacks callbacks;
830 memset(&callbacks, 0, sizeof(jvmtiEventCallbacks));
831 callbacks.GarbageCollectionFinish = GarbageCollectionFinish;
832 callbacks.GarbageCollectionStart = GarbageCollectionStart;
833
834 jvmtiError ret = jvmti_env->SetEventCallbacks(&callbacks, sizeof(callbacks));
835 JvmtiErrorToException(env, jvmti_env, ret);
836 }
837
Java_art_Test913_enableGcTracking(JNIEnv * env,jclass klass ATTRIBUTE_UNUSED,jboolean enable)838 extern "C" JNIEXPORT void JNICALL Java_art_Test913_enableGcTracking(JNIEnv* env,
839 jclass klass ATTRIBUTE_UNUSED,
840 jboolean enable) {
841 jvmtiError ret = jvmti_env->SetEventNotificationMode(
842 enable ? JVMTI_ENABLE : JVMTI_DISABLE,
843 JVMTI_EVENT_GARBAGE_COLLECTION_START,
844 nullptr);
845 if (JvmtiErrorToException(env, jvmti_env, ret)) {
846 return;
847 }
848 ret = jvmti_env->SetEventNotificationMode(
849 enable ? JVMTI_ENABLE : JVMTI_DISABLE,
850 JVMTI_EVENT_GARBAGE_COLLECTION_FINISH,
851 nullptr);
852 if (JvmtiErrorToException(env, jvmti_env, ret)) {
853 return;
854 }
855 }
856
Java_art_Test913_getGcStarts(JNIEnv * env ATTRIBUTE_UNUSED,jclass klass ATTRIBUTE_UNUSED)857 extern "C" JNIEXPORT jint JNICALL Java_art_Test913_getGcStarts(JNIEnv* env ATTRIBUTE_UNUSED,
858 jclass klass ATTRIBUTE_UNUSED) {
859 jint result = static_cast<jint>(starts);
860 starts = 0;
861 return result;
862 }
863
Java_art_Test913_getGcFinishes(JNIEnv * env ATTRIBUTE_UNUSED,jclass klass ATTRIBUTE_UNUSED)864 extern "C" JNIEXPORT jint JNICALL Java_art_Test913_getGcFinishes(JNIEnv* env ATTRIBUTE_UNUSED,
865 jclass klass ATTRIBUTE_UNUSED) {
866 jint result = static_cast<jint>(finishes);
867 finishes = 0;
868 return result;
869 }
870
871 using GetObjectHeapId = jvmtiError(*)(jvmtiEnv*, jlong, jint*, ...);
872 static GetObjectHeapId gGetObjectHeapIdFn = nullptr;
873
874 using GetHeapName = jvmtiError(*)(jvmtiEnv*, jint, char**, ...);
875 static GetHeapName gGetHeapNameFn = nullptr;
876
877 using IterateThroughHeapExt = jvmtiError(*)(jvmtiEnv*,
878 jint,
879 jclass,
880 const jvmtiHeapCallbacks*,
881 const void*);
882 static IterateThroughHeapExt gIterateThroughHeapExt = nullptr;
883
884
FreeExtensionFunctionInfo(jvmtiExtensionFunctionInfo * extensions,jint count)885 static void FreeExtensionFunctionInfo(jvmtiExtensionFunctionInfo* extensions, jint count) {
886 for (size_t i = 0; i != static_cast<size_t>(count); ++i) {
887 jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(extensions[i].id));
888 jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(extensions[i].short_description));
889 for (size_t j = 0; j != static_cast<size_t>(extensions[i].param_count); ++j) {
890 jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(extensions[i].params[j].name));
891 }
892 jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(extensions[i].params));
893 jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(extensions[i].errors));
894 }
895 }
896
Java_art_Test913_checkForExtensionApis(JNIEnv * env,jclass klass ATTRIBUTE_UNUSED)897 extern "C" JNIEXPORT void JNICALL Java_art_Test913_checkForExtensionApis(
898 JNIEnv* env, jclass klass ATTRIBUTE_UNUSED) {
899 jint extension_count;
900 jvmtiExtensionFunctionInfo* extensions;
901 jvmtiError result = jvmti_env->GetExtensionFunctions(&extension_count, &extensions);
902 if (JvmtiErrorToException(env, jvmti_env, result)) {
903 return;
904 }
905
906 for (size_t i = 0; i != static_cast<size_t>(extension_count); ++i) {
907 if (strcmp("com.android.art.heap.get_object_heap_id", extensions[i].id) == 0) {
908 CHECK(gGetObjectHeapIdFn == nullptr);
909 gGetObjectHeapIdFn = reinterpret_cast<GetObjectHeapId>(extensions[i].func);
910
911 CHECK_EQ(extensions[i].param_count, 2);
912
913 CHECK_EQ(strcmp("tag", extensions[i].params[0].name), 0);
914 CHECK_EQ(extensions[i].params[0].base_type, JVMTI_TYPE_JLONG);
915 CHECK_EQ(extensions[i].params[0].kind, JVMTI_KIND_IN);
916
917 CHECK_EQ(strcmp("heap_id", extensions[i].params[1].name), 0);
918 CHECK_EQ(extensions[i].params[1].base_type, JVMTI_TYPE_JINT);
919 CHECK_EQ(extensions[i].params[1].kind, JVMTI_KIND_OUT);
920 CHECK_EQ(extensions[i].params[1].null_ok, false);
921
922 CHECK_EQ(extensions[i].error_count, 1);
923 CHECK(extensions[i].errors != nullptr);
924 CHECK(extensions[i].errors[0] == JVMTI_ERROR_NOT_FOUND);
925
926 continue;
927 }
928
929 if (strcmp("com.android.art.heap.get_heap_name", extensions[i].id) == 0) {
930 CHECK(gGetHeapNameFn == nullptr);
931 gGetHeapNameFn = reinterpret_cast<GetHeapName>(extensions[i].func);
932
933 CHECK_EQ(extensions[i].param_count, 2);
934
935 CHECK_EQ(strcmp("heap_id", extensions[i].params[0].name), 0);
936 CHECK_EQ(extensions[i].params[0].base_type, JVMTI_TYPE_JINT);
937 CHECK_EQ(extensions[i].params[0].kind, JVMTI_KIND_IN);
938
939 CHECK_EQ(strcmp("heap_name", extensions[i].params[1].name), 0);
940 CHECK_EQ(extensions[i].params[1].base_type, JVMTI_TYPE_CCHAR);
941 CHECK_EQ(extensions[i].params[1].kind, JVMTI_KIND_ALLOC_BUF);
942 CHECK_EQ(extensions[i].params[1].null_ok, false);
943
944 CHECK_EQ(extensions[i].error_count, 1);
945 CHECK(extensions[i].errors != nullptr);
946 CHECK(extensions[i].errors[0] == JVMTI_ERROR_ILLEGAL_ARGUMENT);
947 }
948
949 if (strcmp("com.android.art.heap.iterate_through_heap_ext", extensions[i].id) == 0) {
950 CHECK(gIterateThroughHeapExt == nullptr);
951 gIterateThroughHeapExt = reinterpret_cast<IterateThroughHeapExt>(extensions[i].func);
952
953 CHECK_EQ(extensions[i].param_count, 4);
954
955 CHECK_EQ(strcmp("heap_filter", extensions[i].params[0].name), 0);
956 CHECK_EQ(extensions[i].params[0].base_type, JVMTI_TYPE_JINT);
957 CHECK_EQ(extensions[i].params[0].kind, JVMTI_KIND_IN);
958
959 CHECK_EQ(strcmp("klass", extensions[i].params[1].name), 0);
960 CHECK_EQ(extensions[i].params[1].base_type, JVMTI_TYPE_JCLASS);
961 CHECK_EQ(extensions[i].params[1].kind, JVMTI_KIND_IN);
962 CHECK_EQ(extensions[i].params[1].null_ok, true);
963
964 CHECK_EQ(strcmp("callbacks", extensions[i].params[2].name), 0);
965 CHECK_EQ(extensions[i].params[2].base_type, JVMTI_TYPE_CVOID);
966 CHECK_EQ(extensions[i].params[2].kind, JVMTI_KIND_IN_PTR);
967 CHECK_EQ(extensions[i].params[2].null_ok, false);
968
969 CHECK_EQ(strcmp("user_data", extensions[i].params[3].name), 0);
970 CHECK_EQ(extensions[i].params[3].base_type, JVMTI_TYPE_CVOID);
971 CHECK_EQ(extensions[i].params[3].kind, JVMTI_KIND_IN_PTR);
972 CHECK_EQ(extensions[i].params[3].null_ok, true);
973
974 CHECK_EQ(extensions[i].error_count, 3);
975 CHECK(extensions[i].errors != nullptr);
976 CHECK(extensions[i].errors[0] == JVMTI_ERROR_MUST_POSSESS_CAPABILITY);
977 CHECK(extensions[i].errors[1] == JVMTI_ERROR_INVALID_CLASS);
978 CHECK(extensions[i].errors[2] == JVMTI_ERROR_NULL_POINTER);
979 }
980 }
981
982 CHECK(gGetObjectHeapIdFn != nullptr);
983 CHECK(gGetHeapNameFn != nullptr);
984
985 FreeExtensionFunctionInfo(extensions, extension_count);
986 }
987
Java_art_Test913_getObjectHeapId(JNIEnv * env,jclass klass ATTRIBUTE_UNUSED,jlong tag)988 extern "C" JNIEXPORT jint JNICALL Java_art_Test913_getObjectHeapId(
989 JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jlong tag) {
990 CHECK(gGetObjectHeapIdFn != nullptr);
991 jint heap_id;
992 jvmtiError result = gGetObjectHeapIdFn(jvmti_env, tag, &heap_id);
993 JvmtiErrorToException(env, jvmti_env, result);
994 return heap_id;
995 }
996
Java_art_Test913_getHeapName(JNIEnv * env,jclass klass ATTRIBUTE_UNUSED,jint heap_id)997 extern "C" JNIEXPORT jstring JNICALL Java_art_Test913_getHeapName(
998 JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jint heap_id) {
999 CHECK(gGetHeapNameFn != nullptr);
1000 char* heap_name;
1001 jvmtiError result = gGetHeapNameFn(jvmti_env, heap_id, &heap_name);
1002 if (JvmtiErrorToException(env, jvmti_env, result)) {
1003 return nullptr;
1004 }
1005 jstring ret = env->NewStringUTF(heap_name);
1006 jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(heap_name));
1007 return ret;
1008 }
1009
Java_art_Test913_checkGetObjectHeapIdInCallback(JNIEnv * env,jclass klass ATTRIBUTE_UNUSED,jlong tag,jint heap_id)1010 extern "C" JNIEXPORT void JNICALL Java_art_Test913_checkGetObjectHeapIdInCallback(
1011 JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jlong tag, jint heap_id) {
1012 CHECK(gGetObjectHeapIdFn != nullptr);
1013
1014 {
1015 struct GetObjectHeapIdCallbacks {
1016 static jint JNICALL FollowReferencesCallback(
1017 jvmtiHeapReferenceKind reference_kind ATTRIBUTE_UNUSED,
1018 const jvmtiHeapReferenceInfo* reference_info ATTRIBUTE_UNUSED,
1019 jlong class_tag ATTRIBUTE_UNUSED,
1020 jlong referrer_class_tag ATTRIBUTE_UNUSED,
1021 jlong size ATTRIBUTE_UNUSED,
1022 jlong* tag_ptr,
1023 jlong* referrer_tag_ptr ATTRIBUTE_UNUSED,
1024 jint length ATTRIBUTE_UNUSED,
1025 void* user_data) {
1026 if (*tag_ptr != 0) {
1027 GetObjectHeapIdCallbacks* p = reinterpret_cast<GetObjectHeapIdCallbacks*>(user_data);
1028 if (*tag_ptr == p->check_callback_tag) {
1029 jint tag_heap_id;
1030 jvmtiError result = gGetObjectHeapIdFn(jvmti_env, *tag_ptr, &tag_heap_id);
1031 CHECK_EQ(result, JVMTI_ERROR_NONE);
1032 CHECK_EQ(tag_heap_id, p->check_callback_id);
1033 return JVMTI_VISIT_ABORT;
1034 }
1035 }
1036
1037 return JVMTI_VISIT_OBJECTS; // Continue visiting.
1038 }
1039
1040 jlong check_callback_tag;
1041 jint check_callback_id;
1042 };
1043
1044 jvmtiHeapCallbacks callbacks;
1045 memset(&callbacks, 0, sizeof(jvmtiHeapCallbacks));
1046 callbacks.heap_reference_callback = GetObjectHeapIdCallbacks::FollowReferencesCallback;
1047
1048 GetObjectHeapIdCallbacks ffc;
1049 ffc.check_callback_tag = tag;
1050 ffc.check_callback_id = heap_id;
1051
1052 jvmtiError ret = jvmti_env->FollowReferences(0, nullptr, nullptr, &callbacks, &ffc);
1053 if (JvmtiErrorToException(env, jvmti_env, ret)) {
1054 return;
1055 }
1056 }
1057
1058 {
1059 struct GetObjectHeapIdCallbacks {
1060 static jint JNICALL HeapIterationCallback(jlong class_tag ATTRIBUTE_UNUSED,
1061 jlong size ATTRIBUTE_UNUSED,
1062 jlong* tag_ptr,
1063 jint length ATTRIBUTE_UNUSED,
1064 void* user_data) {
1065 if (*tag_ptr != 0) {
1066 GetObjectHeapIdCallbacks* p = reinterpret_cast<GetObjectHeapIdCallbacks*>(user_data);
1067 if (*tag_ptr == p->check_callback_tag) {
1068 jint tag_heap_id;
1069 jvmtiError result = gGetObjectHeapIdFn(jvmti_env, *tag_ptr, &tag_heap_id);
1070 CHECK_EQ(result, JVMTI_ERROR_NONE);
1071 CHECK_EQ(tag_heap_id, p->check_callback_id);
1072 return JVMTI_VISIT_ABORT;
1073 }
1074 }
1075
1076 return 0; // Continue visiting.
1077 }
1078
1079 jlong check_callback_tag;
1080 jint check_callback_id;
1081 };
1082
1083 jvmtiHeapCallbacks callbacks;
1084 memset(&callbacks, 0, sizeof(jvmtiHeapCallbacks));
1085 callbacks.heap_iteration_callback = GetObjectHeapIdCallbacks::HeapIterationCallback;
1086
1087 GetObjectHeapIdCallbacks ffc;
1088 ffc.check_callback_tag = tag;
1089 ffc.check_callback_id = heap_id;
1090
1091 jvmtiError ret = jvmti_env->IterateThroughHeap(0, nullptr, &callbacks, &ffc);
1092 if (JvmtiErrorToException(env, jvmti_env, ret)) {
1093 return;
1094 }
1095 }
1096 }
1097
1098 static bool gFoundExt = false;
1099
HeapIterationExtCallback(jlong class_tag ATTRIBUTE_UNUSED,jlong size ATTRIBUTE_UNUSED,jlong * tag_ptr,jint length ATTRIBUTE_UNUSED,void * user_data ATTRIBUTE_UNUSED,jint heap_id)1100 static jint JNICALL HeapIterationExtCallback(jlong class_tag ATTRIBUTE_UNUSED,
1101 jlong size ATTRIBUTE_UNUSED,
1102 jlong* tag_ptr,
1103 jint length ATTRIBUTE_UNUSED,
1104 void* user_data ATTRIBUTE_UNUSED,
1105 jint heap_id) {
1106 // We expect some tagged objects at or above the threshold, where the expected heap id is
1107 // encoded into lowest byte.
1108 constexpr jlong kThreshold = 30000000;
1109 jlong tag = *tag_ptr;
1110 if (tag >= kThreshold) {
1111 jint expected_heap_id = static_cast<jint>(tag - kThreshold);
1112 CHECK_EQ(expected_heap_id, heap_id);
1113 gFoundExt = true;
1114 }
1115 return 0;
1116 }
1117
Java_art_Test913_iterateThroughHeapExt(JNIEnv * env,jclass klass ATTRIBUTE_UNUSED)1118 extern "C" JNIEXPORT void JNICALL Java_art_Test913_iterateThroughHeapExt(
1119 JNIEnv* env, jclass klass ATTRIBUTE_UNUSED) {
1120 CHECK(gIterateThroughHeapExt != nullptr);
1121
1122 jvmtiHeapCallbacks callbacks;
1123 memset(&callbacks, 0, sizeof(jvmtiHeapCallbacks));
1124 callbacks.heap_iteration_callback =
1125 reinterpret_cast<decltype(callbacks.heap_iteration_callback)>(HeapIterationExtCallback);
1126
1127 jvmtiError ret = gIterateThroughHeapExt(jvmti_env, 0, nullptr, &callbacks, nullptr);
1128 JvmtiErrorToException(env, jvmti_env, ret);
1129 CHECK(gFoundExt);
1130 }
1131
Java_art_Test913_checkInitialized(JNIEnv * env,jclass,jclass c)1132 extern "C" JNIEXPORT jboolean JNICALL Java_art_Test913_checkInitialized(JNIEnv* env, jclass, jclass c) {
1133 jint status;
1134 jvmtiError error = jvmti_env->GetClassStatus(c, &status);
1135 if (JvmtiErrorToException(env, jvmti_env, error)) {
1136 return false;
1137 }
1138 return (status & JVMTI_CLASS_STATUS_INITIALIZED) != 0;
1139 }
1140
1141 } // namespace Test913Heaps
1142 } // namespace art
1143