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