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