xref: /aosp_15_r20/art/test/906-iterate-heap/iterate_heap.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 #include <pthread.h>
19*795d594fSAndroid Build Coastguard Worker 
20*795d594fSAndroid Build Coastguard Worker #include <cstdio>
21*795d594fSAndroid Build Coastguard Worker #include <iomanip>
22*795d594fSAndroid Build Coastguard Worker #include <iostream>
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/stringprintf.h"
28*795d594fSAndroid Build Coastguard Worker 
29*795d594fSAndroid Build Coastguard Worker #include "jni.h"
30*795d594fSAndroid Build Coastguard Worker #include "jvmti.h"
31*795d594fSAndroid Build Coastguard Worker #include "scoped_primitive_array.h"
32*795d594fSAndroid Build Coastguard Worker 
33*795d594fSAndroid Build Coastguard Worker // Test infrastructure
34*795d594fSAndroid Build Coastguard Worker #include "jvmti_helper.h"
35*795d594fSAndroid Build Coastguard Worker #include "test_env.h"
36*795d594fSAndroid Build Coastguard Worker #include "ti_macros.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 Test906IterateHeap {
41*795d594fSAndroid Build Coastguard Worker 
42*795d594fSAndroid Build Coastguard Worker class IterationConfig {
43*795d594fSAndroid Build Coastguard Worker  public:
IterationConfig()44*795d594fSAndroid Build Coastguard Worker   IterationConfig() {}
~IterationConfig()45*795d594fSAndroid Build Coastguard Worker   virtual ~IterationConfig() {}
46*795d594fSAndroid Build Coastguard Worker 
47*795d594fSAndroid Build Coastguard Worker   virtual jint Handle(jlong class_tag, jlong size, jlong* tag_ptr, jint length) = 0;
48*795d594fSAndroid Build Coastguard Worker };
49*795d594fSAndroid Build Coastguard Worker 
HeapIterationCallback(jlong class_tag,jlong size,jlong * tag_ptr,jint length,void * user_data)50*795d594fSAndroid Build Coastguard Worker static jint JNICALL HeapIterationCallback(jlong class_tag,
51*795d594fSAndroid Build Coastguard Worker                                           jlong size,
52*795d594fSAndroid Build Coastguard Worker                                           jlong* tag_ptr,
53*795d594fSAndroid Build Coastguard Worker                                           jint length,
54*795d594fSAndroid Build Coastguard Worker                                           void* user_data) {
55*795d594fSAndroid Build Coastguard Worker   IterationConfig* config = reinterpret_cast<IterationConfig*>(user_data);
56*795d594fSAndroid Build Coastguard Worker   return config->Handle(class_tag, size, tag_ptr, length);
57*795d594fSAndroid Build Coastguard Worker }
58*795d594fSAndroid Build Coastguard Worker 
Run(JNIEnv * env,jint heap_filter,jclass klass_filter,IterationConfig * config)59*795d594fSAndroid Build Coastguard Worker static bool Run(JNIEnv* env, jint heap_filter, jclass klass_filter, IterationConfig* config) {
60*795d594fSAndroid Build Coastguard Worker   jvmtiHeapCallbacks callbacks;
61*795d594fSAndroid Build Coastguard Worker   memset(&callbacks, 0, sizeof(jvmtiHeapCallbacks));
62*795d594fSAndroid Build Coastguard Worker   callbacks.heap_iteration_callback = HeapIterationCallback;
63*795d594fSAndroid Build Coastguard Worker 
64*795d594fSAndroid Build Coastguard Worker   jvmtiError ret = jvmti_env->IterateThroughHeap(heap_filter,
65*795d594fSAndroid Build Coastguard Worker                                                  klass_filter,
66*795d594fSAndroid Build Coastguard Worker                                                  &callbacks,
67*795d594fSAndroid Build Coastguard Worker                                                  config);
68*795d594fSAndroid Build Coastguard Worker   if (JvmtiErrorToException(env, jvmti_env, ret)) {
69*795d594fSAndroid Build Coastguard Worker     return false;
70*795d594fSAndroid Build Coastguard Worker   }
71*795d594fSAndroid Build Coastguard Worker   return true;
72*795d594fSAndroid Build Coastguard Worker }
73*795d594fSAndroid Build Coastguard Worker 
Java_art_Test906_iterateThroughHeapCount(JNIEnv * env,jclass klass,jint heap_filter,jclass klass_filter,jint stop_after)74*795d594fSAndroid Build Coastguard Worker extern "C" JNIEXPORT jint JNICALL Java_art_Test906_iterateThroughHeapCount(
75*795d594fSAndroid Build Coastguard Worker     JNIEnv* env,
76*795d594fSAndroid Build Coastguard Worker     [[maybe_unused]] jclass klass,
77*795d594fSAndroid Build Coastguard Worker     jint heap_filter,
78*795d594fSAndroid Build Coastguard Worker     jclass klass_filter,
79*795d594fSAndroid Build Coastguard Worker     jint stop_after) {
80*795d594fSAndroid Build Coastguard Worker   class CountIterationConfig : public IterationConfig {
81*795d594fSAndroid Build Coastguard Worker    public:
82*795d594fSAndroid Build Coastguard Worker     CountIterationConfig(jint _counter, jint _stop_after)
83*795d594fSAndroid Build Coastguard Worker         : counter(_counter),
84*795d594fSAndroid Build Coastguard Worker           stop_after(_stop_after) {
85*795d594fSAndroid Build Coastguard Worker     }
86*795d594fSAndroid Build Coastguard Worker 
87*795d594fSAndroid Build Coastguard Worker     jint Handle([[maybe_unused]] jlong class_tag,
88*795d594fSAndroid Build Coastguard Worker                 [[maybe_unused]] jlong size,
89*795d594fSAndroid Build Coastguard Worker                 [[maybe_unused]] jlong* tag_ptr,
90*795d594fSAndroid Build Coastguard Worker                 [[maybe_unused]] jint length) override {
91*795d594fSAndroid Build Coastguard Worker       counter++;
92*795d594fSAndroid Build Coastguard Worker       if (counter == stop_after) {
93*795d594fSAndroid Build Coastguard Worker         return JVMTI_VISIT_ABORT;
94*795d594fSAndroid Build Coastguard Worker       }
95*795d594fSAndroid Build Coastguard Worker       return 0;
96*795d594fSAndroid Build Coastguard Worker     }
97*795d594fSAndroid Build Coastguard Worker 
98*795d594fSAndroid Build Coastguard Worker     jint counter;
99*795d594fSAndroid Build Coastguard Worker     const jint stop_after;
100*795d594fSAndroid Build Coastguard Worker   };
101*795d594fSAndroid Build Coastguard Worker 
102*795d594fSAndroid Build Coastguard Worker   CountIterationConfig config(0, stop_after);
103*795d594fSAndroid Build Coastguard Worker   Run(env, heap_filter, klass_filter, &config);
104*795d594fSAndroid Build Coastguard Worker 
105*795d594fSAndroid Build Coastguard Worker   if (config.counter > config.stop_after) {
106*795d594fSAndroid Build Coastguard Worker     printf("Error: more objects visited than signaled.");
107*795d594fSAndroid Build Coastguard Worker   }
108*795d594fSAndroid Build Coastguard Worker 
109*795d594fSAndroid Build Coastguard Worker   return config.counter;
110*795d594fSAndroid Build Coastguard Worker }
111*795d594fSAndroid Build Coastguard Worker 
Java_art_Test906_iterateThroughHeapData(JNIEnv * env,jclass klass,jint heap_filter,jclass klass_filter,jlongArray class_tags,jlongArray sizes,jlongArray tags,jintArray lengths)112*795d594fSAndroid Build Coastguard Worker extern "C" JNIEXPORT jint JNICALL Java_art_Test906_iterateThroughHeapData(
113*795d594fSAndroid Build Coastguard Worker     JNIEnv* env,
114*795d594fSAndroid Build Coastguard Worker     [[maybe_unused]] jclass klass,
115*795d594fSAndroid Build Coastguard Worker     jint heap_filter,
116*795d594fSAndroid Build Coastguard Worker     jclass klass_filter,
117*795d594fSAndroid Build Coastguard Worker     jlongArray class_tags,
118*795d594fSAndroid Build Coastguard Worker     jlongArray sizes,
119*795d594fSAndroid Build Coastguard Worker     jlongArray tags,
120*795d594fSAndroid Build Coastguard Worker     jintArray lengths) {
121*795d594fSAndroid Build Coastguard Worker   class DataIterationConfig : public IterationConfig {
122*795d594fSAndroid Build Coastguard Worker    public:
123*795d594fSAndroid Build Coastguard Worker     jint Handle(jlong class_tag, jlong size, jlong* tag_ptr, jint length) override {
124*795d594fSAndroid Build Coastguard Worker       class_tags_.push_back(class_tag);
125*795d594fSAndroid Build Coastguard Worker       sizes_.push_back(size);
126*795d594fSAndroid Build Coastguard Worker       tags_.push_back(*tag_ptr);
127*795d594fSAndroid Build Coastguard Worker       lengths_.push_back(length);
128*795d594fSAndroid Build Coastguard Worker 
129*795d594fSAndroid Build Coastguard Worker       return 0;  // Continue.
130*795d594fSAndroid Build Coastguard Worker     }
131*795d594fSAndroid Build Coastguard Worker 
132*795d594fSAndroid Build Coastguard Worker     std::vector<jlong> class_tags_;
133*795d594fSAndroid Build Coastguard Worker     std::vector<jlong> sizes_;
134*795d594fSAndroid Build Coastguard Worker     std::vector<jlong> tags_;
135*795d594fSAndroid Build Coastguard Worker     std::vector<jint> lengths_;
136*795d594fSAndroid Build Coastguard Worker   };
137*795d594fSAndroid Build Coastguard Worker 
138*795d594fSAndroid Build Coastguard Worker   DataIterationConfig config;
139*795d594fSAndroid Build Coastguard Worker   if (!Run(env, heap_filter, klass_filter, &config)) {
140*795d594fSAndroid Build Coastguard Worker     return -1;
141*795d594fSAndroid Build Coastguard Worker   }
142*795d594fSAndroid Build Coastguard Worker 
143*795d594fSAndroid Build Coastguard Worker   ScopedLongArrayRW s_class_tags(env, class_tags);
144*795d594fSAndroid Build Coastguard Worker   ScopedLongArrayRW s_sizes(env, sizes);
145*795d594fSAndroid Build Coastguard Worker   ScopedLongArrayRW s_tags(env, tags);
146*795d594fSAndroid Build Coastguard Worker   ScopedIntArrayRW s_lengths(env, lengths);
147*795d594fSAndroid Build Coastguard Worker 
148*795d594fSAndroid Build Coastguard Worker   for (size_t i = 0; i != config.class_tags_.size(); ++i) {
149*795d594fSAndroid Build Coastguard Worker     s_class_tags[i] = config.class_tags_[i];
150*795d594fSAndroid Build Coastguard Worker     s_sizes[i] = config.sizes_[i];
151*795d594fSAndroid Build Coastguard Worker     s_tags[i] = config.tags_[i];
152*795d594fSAndroid Build Coastguard Worker     s_lengths[i] = config.lengths_[i];
153*795d594fSAndroid Build Coastguard Worker   }
154*795d594fSAndroid Build Coastguard Worker 
155*795d594fSAndroid Build Coastguard Worker   return static_cast<jint>(config.class_tags_.size());
156*795d594fSAndroid Build Coastguard Worker }
157*795d594fSAndroid Build Coastguard Worker 
Java_art_Test906_iterateThroughHeapAdd(JNIEnv * env,jclass klass,jint heap_filter,jclass klass_filter)158*795d594fSAndroid Build Coastguard Worker extern "C" JNIEXPORT void JNICALL Java_art_Test906_iterateThroughHeapAdd(
159*795d594fSAndroid Build Coastguard Worker     JNIEnv* env, [[maybe_unused]] jclass klass, jint heap_filter, jclass klass_filter) {
160*795d594fSAndroid Build Coastguard Worker   class AddIterationConfig : public IterationConfig {
161*795d594fSAndroid Build Coastguard Worker    public:
162*795d594fSAndroid Build Coastguard Worker     AddIterationConfig() {}
163*795d594fSAndroid Build Coastguard Worker 
164*795d594fSAndroid Build Coastguard Worker     jint Handle([[maybe_unused]] jlong class_tag,
165*795d594fSAndroid Build Coastguard Worker                 [[maybe_unused]] jlong size,
166*795d594fSAndroid Build Coastguard Worker                 jlong* tag_ptr,
167*795d594fSAndroid Build Coastguard Worker                 [[maybe_unused]] jint length) override {
168*795d594fSAndroid Build Coastguard Worker       jlong current_tag = *tag_ptr;
169*795d594fSAndroid Build Coastguard Worker       if (current_tag != 0) {
170*795d594fSAndroid Build Coastguard Worker         *tag_ptr = current_tag + 10;
171*795d594fSAndroid Build Coastguard Worker       }
172*795d594fSAndroid Build Coastguard Worker       return 0;
173*795d594fSAndroid Build Coastguard Worker     }
174*795d594fSAndroid Build Coastguard Worker   };
175*795d594fSAndroid Build Coastguard Worker 
176*795d594fSAndroid Build Coastguard Worker   AddIterationConfig config;
177*795d594fSAndroid Build Coastguard Worker   Run(env, heap_filter, klass_filter, &config);
178*795d594fSAndroid Build Coastguard Worker }
179*795d594fSAndroid Build Coastguard Worker 
Java_art_Test906_iterateThroughHeapString(JNIEnv * env,jclass klass,jlong tag)180*795d594fSAndroid Build Coastguard Worker extern "C" JNIEXPORT jstring JNICALL Java_art_Test906_iterateThroughHeapString(
181*795d594fSAndroid Build Coastguard Worker     JNIEnv* env, [[maybe_unused]] jclass klass, jlong tag) {
182*795d594fSAndroid Build Coastguard Worker   struct FindStringCallbacks {
183*795d594fSAndroid Build Coastguard Worker     explicit FindStringCallbacks(jlong t) : tag_to_find(t) {}
184*795d594fSAndroid Build Coastguard Worker 
185*795d594fSAndroid Build Coastguard Worker     static jint JNICALL HeapIterationCallback([[maybe_unused]] jlong class_tag,
186*795d594fSAndroid Build Coastguard Worker                                               [[maybe_unused]] jlong size,
187*795d594fSAndroid Build Coastguard Worker                                               [[maybe_unused]] jlong* tag_ptr,
188*795d594fSAndroid Build Coastguard Worker                                               [[maybe_unused]] jint length,
189*795d594fSAndroid Build Coastguard Worker                                               [[maybe_unused]] void* user_data) {
190*795d594fSAndroid Build Coastguard Worker       return 0;
191*795d594fSAndroid Build Coastguard Worker     }
192*795d594fSAndroid Build Coastguard Worker 
193*795d594fSAndroid Build Coastguard Worker     static jint JNICALL StringValueCallback(jlong class_tag,
194*795d594fSAndroid Build Coastguard Worker                                             jlong size,
195*795d594fSAndroid Build Coastguard Worker                                             jlong* tag_ptr,
196*795d594fSAndroid Build Coastguard Worker                                             const jchar* value,
197*795d594fSAndroid Build Coastguard Worker                                             jint value_length,
198*795d594fSAndroid Build Coastguard Worker                                             void* user_data) {
199*795d594fSAndroid Build Coastguard Worker       FindStringCallbacks* p = reinterpret_cast<FindStringCallbacks*>(user_data);
200*795d594fSAndroid Build Coastguard Worker       if (*tag_ptr == p->tag_to_find) {
201*795d594fSAndroid Build Coastguard Worker         size_t utf_byte_count = ti::CountModifiedUtf8BytesInUtf16(value, value_length);
202*795d594fSAndroid Build Coastguard Worker         std::unique_ptr<char[]> mod_utf(new char[utf_byte_count + 1]);
203*795d594fSAndroid Build Coastguard Worker         memset(mod_utf.get(), 0, utf_byte_count + 1);
204*795d594fSAndroid Build Coastguard Worker         ti::ConvertUtf16ToModifiedUtf8(mod_utf.get(), utf_byte_count, value, value_length);
205*795d594fSAndroid Build Coastguard Worker         if (!p->data.empty()) {
206*795d594fSAndroid Build Coastguard Worker           p->data += "\n";
207*795d594fSAndroid Build Coastguard Worker         }
208*795d594fSAndroid Build Coastguard Worker         p->data += android::base::StringPrintf("%" PRId64 "@%" PRId64 " (%" PRId64 ", '%s')",
209*795d594fSAndroid Build Coastguard Worker                                                *tag_ptr,
210*795d594fSAndroid Build Coastguard Worker                                                class_tag,
211*795d594fSAndroid Build Coastguard Worker                                                size,
212*795d594fSAndroid Build Coastguard Worker                                                mod_utf.get());
213*795d594fSAndroid Build Coastguard Worker         // Update the tag to test whether that works.
214*795d594fSAndroid Build Coastguard Worker         *tag_ptr = *tag_ptr + 1;
215*795d594fSAndroid Build Coastguard Worker       }
216*795d594fSAndroid Build Coastguard Worker       return 0;
217*795d594fSAndroid Build Coastguard Worker     }
218*795d594fSAndroid Build Coastguard Worker 
219*795d594fSAndroid Build Coastguard Worker     std::string data;
220*795d594fSAndroid Build Coastguard Worker     const jlong tag_to_find;
221*795d594fSAndroid Build Coastguard Worker   };
222*795d594fSAndroid Build Coastguard Worker 
223*795d594fSAndroid Build Coastguard Worker   jvmtiHeapCallbacks callbacks;
224*795d594fSAndroid Build Coastguard Worker   memset(&callbacks, 0, sizeof(jvmtiHeapCallbacks));
225*795d594fSAndroid Build Coastguard Worker   callbacks.heap_iteration_callback = FindStringCallbacks::HeapIterationCallback;
226*795d594fSAndroid Build Coastguard Worker   callbacks.string_primitive_value_callback = FindStringCallbacks::StringValueCallback;
227*795d594fSAndroid Build Coastguard Worker 
228*795d594fSAndroid Build Coastguard Worker   FindStringCallbacks fsc(tag);
229*795d594fSAndroid Build Coastguard Worker   jvmtiError ret = jvmti_env->IterateThroughHeap(0, nullptr, &callbacks, &fsc);
230*795d594fSAndroid Build Coastguard Worker   if (JvmtiErrorToException(env, jvmti_env, ret)) {
231*795d594fSAndroid Build Coastguard Worker     return nullptr;
232*795d594fSAndroid Build Coastguard Worker   }
233*795d594fSAndroid Build Coastguard Worker   return env->NewStringUTF(fsc.data.c_str());
234*795d594fSAndroid Build Coastguard Worker }
235*795d594fSAndroid Build Coastguard Worker 
Java_art_Test906_iterateThroughHeapPrimitiveArray(JNIEnv * env,jclass klass,jlong tag)236*795d594fSAndroid Build Coastguard Worker extern "C" JNIEXPORT jstring JNICALL Java_art_Test906_iterateThroughHeapPrimitiveArray(
237*795d594fSAndroid Build Coastguard Worker     JNIEnv* env, [[maybe_unused]] jclass klass, jlong tag) {
238*795d594fSAndroid Build Coastguard Worker   struct FindArrayCallbacks {
239*795d594fSAndroid Build Coastguard Worker     explicit FindArrayCallbacks(jlong t) : tag_to_find(t) {}
240*795d594fSAndroid Build Coastguard Worker 
241*795d594fSAndroid Build Coastguard Worker     static jint JNICALL HeapIterationCallback([[maybe_unused]] jlong class_tag,
242*795d594fSAndroid Build Coastguard Worker                                               [[maybe_unused]] jlong size,
243*795d594fSAndroid Build Coastguard Worker                                               [[maybe_unused]] jlong* tag_ptr,
244*795d594fSAndroid Build Coastguard Worker                                               [[maybe_unused]] jint length,
245*795d594fSAndroid Build Coastguard Worker                                               [[maybe_unused]] void* user_data) {
246*795d594fSAndroid Build Coastguard Worker       return 0;
247*795d594fSAndroid Build Coastguard Worker     }
248*795d594fSAndroid Build Coastguard Worker 
249*795d594fSAndroid Build Coastguard Worker     static jint JNICALL ArrayValueCallback(jlong class_tag,
250*795d594fSAndroid Build Coastguard Worker                                            jlong size,
251*795d594fSAndroid Build Coastguard Worker                                            jlong* tag_ptr,
252*795d594fSAndroid Build Coastguard Worker                                            jint element_count,
253*795d594fSAndroid Build Coastguard Worker                                            jvmtiPrimitiveType element_type,
254*795d594fSAndroid Build Coastguard Worker                                            const void* elements,
255*795d594fSAndroid Build Coastguard Worker                                            void* user_data) {
256*795d594fSAndroid Build Coastguard Worker       FindArrayCallbacks* p = reinterpret_cast<FindArrayCallbacks*>(user_data);
257*795d594fSAndroid Build Coastguard Worker       if (*tag_ptr == p->tag_to_find) {
258*795d594fSAndroid Build Coastguard Worker         std::ostringstream oss;
259*795d594fSAndroid Build Coastguard Worker         oss << *tag_ptr
260*795d594fSAndroid Build Coastguard Worker             << '@'
261*795d594fSAndroid Build Coastguard Worker             << class_tag
262*795d594fSAndroid Build Coastguard Worker             << " ("
263*795d594fSAndroid Build Coastguard Worker             << size
264*795d594fSAndroid Build Coastguard Worker             << ", "
265*795d594fSAndroid Build Coastguard Worker             << element_count
266*795d594fSAndroid Build Coastguard Worker             << "x"
267*795d594fSAndroid Build Coastguard Worker             << static_cast<char>(element_type)
268*795d594fSAndroid Build Coastguard Worker             << " '";
269*795d594fSAndroid Build Coastguard Worker         size_t element_size;
270*795d594fSAndroid Build Coastguard Worker         switch (element_type) {
271*795d594fSAndroid Build Coastguard Worker           case JVMTI_PRIMITIVE_TYPE_BOOLEAN:
272*795d594fSAndroid Build Coastguard Worker           case JVMTI_PRIMITIVE_TYPE_BYTE:
273*795d594fSAndroid Build Coastguard Worker             element_size = 1;
274*795d594fSAndroid Build Coastguard Worker             break;
275*795d594fSAndroid Build Coastguard Worker           case JVMTI_PRIMITIVE_TYPE_CHAR:
276*795d594fSAndroid Build Coastguard Worker           case JVMTI_PRIMITIVE_TYPE_SHORT:
277*795d594fSAndroid Build Coastguard Worker             element_size = 2;
278*795d594fSAndroid Build Coastguard Worker             break;
279*795d594fSAndroid Build Coastguard Worker           case JVMTI_PRIMITIVE_TYPE_INT:
280*795d594fSAndroid Build Coastguard Worker           case JVMTI_PRIMITIVE_TYPE_FLOAT:
281*795d594fSAndroid Build Coastguard Worker             element_size = 4;
282*795d594fSAndroid Build Coastguard Worker             break;
283*795d594fSAndroid Build Coastguard Worker           case JVMTI_PRIMITIVE_TYPE_LONG:
284*795d594fSAndroid Build Coastguard Worker           case JVMTI_PRIMITIVE_TYPE_DOUBLE:
285*795d594fSAndroid Build Coastguard Worker             element_size = 8;
286*795d594fSAndroid Build Coastguard Worker             break;
287*795d594fSAndroid Build Coastguard Worker         }
288*795d594fSAndroid Build Coastguard Worker         const uint8_t* data = reinterpret_cast<const uint8_t*>(elements);
289*795d594fSAndroid Build Coastguard Worker         for (size_t i = 0; i != element_size * element_count; ++i) {
290*795d594fSAndroid Build Coastguard Worker           oss << android::base::StringPrintf("%02x", data[i]);
291*795d594fSAndroid Build Coastguard Worker         }
292*795d594fSAndroid Build Coastguard Worker         oss << "')";
293*795d594fSAndroid Build Coastguard Worker 
294*795d594fSAndroid Build Coastguard Worker         if (!p->data.empty()) {
295*795d594fSAndroid Build Coastguard Worker           p->data += "\n";
296*795d594fSAndroid Build Coastguard Worker         }
297*795d594fSAndroid Build Coastguard Worker         p->data += oss.str();
298*795d594fSAndroid Build Coastguard Worker         // Update the tag to test whether that works.
299*795d594fSAndroid Build Coastguard Worker         *tag_ptr = *tag_ptr + 1;
300*795d594fSAndroid Build Coastguard Worker       }
301*795d594fSAndroid Build Coastguard Worker       return 0;
302*795d594fSAndroid Build Coastguard Worker     }
303*795d594fSAndroid Build Coastguard Worker 
304*795d594fSAndroid Build Coastguard Worker     std::string data;
305*795d594fSAndroid Build Coastguard Worker     const jlong tag_to_find;
306*795d594fSAndroid Build Coastguard Worker   };
307*795d594fSAndroid Build Coastguard Worker 
308*795d594fSAndroid Build Coastguard Worker   jvmtiHeapCallbacks callbacks;
309*795d594fSAndroid Build Coastguard Worker   memset(&callbacks, 0, sizeof(jvmtiHeapCallbacks));
310*795d594fSAndroid Build Coastguard Worker   callbacks.heap_iteration_callback = FindArrayCallbacks::HeapIterationCallback;
311*795d594fSAndroid Build Coastguard Worker   callbacks.array_primitive_value_callback = FindArrayCallbacks::ArrayValueCallback;
312*795d594fSAndroid Build Coastguard Worker 
313*795d594fSAndroid Build Coastguard Worker   FindArrayCallbacks fac(tag);
314*795d594fSAndroid Build Coastguard Worker   jvmtiError ret = jvmti_env->IterateThroughHeap(0, nullptr, &callbacks, &fac);
315*795d594fSAndroid Build Coastguard Worker   if (JvmtiErrorToException(env, jvmti_env, ret)) {
316*795d594fSAndroid Build Coastguard Worker     return nullptr;
317*795d594fSAndroid Build Coastguard Worker   }
318*795d594fSAndroid Build Coastguard Worker   return env->NewStringUTF(fac.data.c_str());
319*795d594fSAndroid Build Coastguard Worker }
320*795d594fSAndroid Build Coastguard Worker 
GetPrimitiveTypeName(jvmtiPrimitiveType type)321*795d594fSAndroid Build Coastguard Worker static constexpr const char* GetPrimitiveTypeName(jvmtiPrimitiveType type) {
322*795d594fSAndroid Build Coastguard Worker   switch (type) {
323*795d594fSAndroid Build Coastguard Worker     case JVMTI_PRIMITIVE_TYPE_BOOLEAN:
324*795d594fSAndroid Build Coastguard Worker       return "boolean";
325*795d594fSAndroid Build Coastguard Worker     case JVMTI_PRIMITIVE_TYPE_BYTE:
326*795d594fSAndroid Build Coastguard Worker       return "byte";
327*795d594fSAndroid Build Coastguard Worker     case JVMTI_PRIMITIVE_TYPE_CHAR:
328*795d594fSAndroid Build Coastguard Worker       return "char";
329*795d594fSAndroid Build Coastguard Worker     case JVMTI_PRIMITIVE_TYPE_SHORT:
330*795d594fSAndroid Build Coastguard Worker       return "short";
331*795d594fSAndroid Build Coastguard Worker     case JVMTI_PRIMITIVE_TYPE_INT:
332*795d594fSAndroid Build Coastguard Worker       return "int";
333*795d594fSAndroid Build Coastguard Worker     case JVMTI_PRIMITIVE_TYPE_FLOAT:
334*795d594fSAndroid Build Coastguard Worker       return "float";
335*795d594fSAndroid Build Coastguard Worker     case JVMTI_PRIMITIVE_TYPE_LONG:
336*795d594fSAndroid Build Coastguard Worker       return "long";
337*795d594fSAndroid Build Coastguard Worker     case JVMTI_PRIMITIVE_TYPE_DOUBLE:
338*795d594fSAndroid Build Coastguard Worker       return "double";
339*795d594fSAndroid Build Coastguard Worker   }
340*795d594fSAndroid Build Coastguard Worker   LOG(FATAL) << "Unknown type " << static_cast<size_t>(type);
341*795d594fSAndroid Build Coastguard Worker   UNREACHABLE();
342*795d594fSAndroid Build Coastguard Worker }
343*795d594fSAndroid Build Coastguard Worker 
Java_art_Test906_iterateThroughHeapPrimitiveFields(JNIEnv * env,jclass klass,jlong tag)344*795d594fSAndroid Build Coastguard Worker extern "C" JNIEXPORT jstring JNICALL Java_art_Test906_iterateThroughHeapPrimitiveFields(
345*795d594fSAndroid Build Coastguard Worker     JNIEnv* env, [[maybe_unused]] jclass klass, jlong tag) {
346*795d594fSAndroid Build Coastguard Worker   struct FindFieldCallbacks {
347*795d594fSAndroid Build Coastguard Worker     explicit FindFieldCallbacks(jlong t) : tag_to_find(t) {}
348*795d594fSAndroid Build Coastguard Worker 
349*795d594fSAndroid Build Coastguard Worker     static jint JNICALL HeapIterationCallback([[maybe_unused]] jlong class_tag,
350*795d594fSAndroid Build Coastguard Worker                                               [[maybe_unused]] jlong size,
351*795d594fSAndroid Build Coastguard Worker                                               [[maybe_unused]] jlong* tag_ptr,
352*795d594fSAndroid Build Coastguard Worker                                               [[maybe_unused]] jint length,
353*795d594fSAndroid Build Coastguard Worker                                               [[maybe_unused]] void* user_data) {
354*795d594fSAndroid Build Coastguard Worker       return 0;
355*795d594fSAndroid Build Coastguard Worker     }
356*795d594fSAndroid Build Coastguard Worker 
357*795d594fSAndroid Build Coastguard Worker     static jint JNICALL PrimitiveFieldValueCallback(jvmtiHeapReferenceKind kind,
358*795d594fSAndroid Build Coastguard Worker                                                     const jvmtiHeapReferenceInfo* info,
359*795d594fSAndroid Build Coastguard Worker                                                     jlong class_tag,
360*795d594fSAndroid Build Coastguard Worker                                                     jlong* tag_ptr,
361*795d594fSAndroid Build Coastguard Worker                                                     jvalue value,
362*795d594fSAndroid Build Coastguard Worker                                                     jvmtiPrimitiveType value_type,
363*795d594fSAndroid Build Coastguard Worker                                                     void* user_data) {
364*795d594fSAndroid Build Coastguard Worker       FindFieldCallbacks* p = reinterpret_cast<FindFieldCallbacks*>(user_data);
365*795d594fSAndroid Build Coastguard Worker       if (*tag_ptr >= p->tag_to_find) {
366*795d594fSAndroid Build Coastguard Worker         std::ostringstream oss;
367*795d594fSAndroid Build Coastguard Worker         oss << *tag_ptr
368*795d594fSAndroid Build Coastguard Worker             << '@'
369*795d594fSAndroid Build Coastguard Worker             << class_tag
370*795d594fSAndroid Build Coastguard Worker             << " ("
371*795d594fSAndroid Build Coastguard Worker             << (kind == JVMTI_HEAP_REFERENCE_FIELD ? "instance, " : "static, ")
372*795d594fSAndroid Build Coastguard Worker             << GetPrimitiveTypeName(value_type)
373*795d594fSAndroid Build Coastguard Worker             << ", index="
374*795d594fSAndroid Build Coastguard Worker             << info->field.index
375*795d594fSAndroid Build Coastguard Worker             << ") ";
376*795d594fSAndroid Build Coastguard Worker         // Be lazy, always print eight bytes.
377*795d594fSAndroid Build Coastguard Worker         static_assert(sizeof(jvalue) == sizeof(uint64_t), "Unexpected jvalue size");
378*795d594fSAndroid Build Coastguard Worker         uint64_t val;
379*795d594fSAndroid Build Coastguard Worker         memcpy(&val, &value, sizeof(uint64_t));  // To avoid undefined behavior.
380*795d594fSAndroid Build Coastguard Worker         oss << android::base::StringPrintf("%016" PRIx64, val);
381*795d594fSAndroid Build Coastguard Worker 
382*795d594fSAndroid Build Coastguard Worker         if (!p->data.empty()) {
383*795d594fSAndroid Build Coastguard Worker           p->data += "\n";
384*795d594fSAndroid Build Coastguard Worker         }
385*795d594fSAndroid Build Coastguard Worker         p->data += oss.str();
386*795d594fSAndroid Build Coastguard Worker         *tag_ptr = *tag_ptr + 1;
387*795d594fSAndroid Build Coastguard Worker       }
388*795d594fSAndroid Build Coastguard Worker       return 0;
389*795d594fSAndroid Build Coastguard Worker     }
390*795d594fSAndroid Build Coastguard Worker 
391*795d594fSAndroid Build Coastguard Worker     std::string data;
392*795d594fSAndroid Build Coastguard Worker     const jlong tag_to_find;
393*795d594fSAndroid Build Coastguard Worker   };
394*795d594fSAndroid Build Coastguard Worker 
395*795d594fSAndroid Build Coastguard Worker   jvmtiHeapCallbacks callbacks;
396*795d594fSAndroid Build Coastguard Worker   memset(&callbacks, 0, sizeof(jvmtiHeapCallbacks));
397*795d594fSAndroid Build Coastguard Worker   callbacks.heap_iteration_callback = FindFieldCallbacks::HeapIterationCallback;
398*795d594fSAndroid Build Coastguard Worker   callbacks.primitive_field_callback = FindFieldCallbacks::PrimitiveFieldValueCallback;
399*795d594fSAndroid Build Coastguard Worker 
400*795d594fSAndroid Build Coastguard Worker   FindFieldCallbacks ffc(tag);
401*795d594fSAndroid Build Coastguard Worker   jvmtiError ret = jvmti_env->IterateThroughHeap(0, nullptr, &callbacks, &ffc);
402*795d594fSAndroid Build Coastguard Worker   if (JvmtiErrorToException(env, jvmti_env, ret)) {
403*795d594fSAndroid Build Coastguard Worker     return nullptr;
404*795d594fSAndroid Build Coastguard Worker   }
405*795d594fSAndroid Build Coastguard Worker   return env->NewStringUTF(ffc.data.c_str());
406*795d594fSAndroid Build Coastguard Worker }
407*795d594fSAndroid Build Coastguard Worker 
Java_art_Test906_checkInitialized(JNIEnv * env,jclass,jclass c)408*795d594fSAndroid Build Coastguard Worker extern "C" JNIEXPORT jboolean JNICALL Java_art_Test906_checkInitialized(
409*795d594fSAndroid Build Coastguard Worker     JNIEnv* env, jclass, jclass c) {
410*795d594fSAndroid Build Coastguard Worker   jint status;
411*795d594fSAndroid Build Coastguard Worker   jvmtiError error = jvmti_env->GetClassStatus(c, &status);
412*795d594fSAndroid Build Coastguard Worker   if (JvmtiErrorToException(env, jvmti_env, error)) {
413*795d594fSAndroid Build Coastguard Worker     return false;
414*795d594fSAndroid Build Coastguard Worker   }
415*795d594fSAndroid Build Coastguard Worker   return (status & JVMTI_CLASS_STATUS_INITIALIZED) != 0;
416*795d594fSAndroid Build Coastguard Worker }
417*795d594fSAndroid Build Coastguard Worker 
Java_art_Test906_iterateOverInstancesCount(JNIEnv * env,jclass,jclass target)418*795d594fSAndroid Build Coastguard Worker extern "C" JNIEXPORT jint JNICALL Java_art_Test906_iterateOverInstancesCount(
419*795d594fSAndroid Build Coastguard Worker     JNIEnv* env, jclass, jclass target) {
420*795d594fSAndroid Build Coastguard Worker   jint cnt = 0;
421*795d594fSAndroid Build Coastguard Worker   auto count_func = [](jlong, jlong, jlong*, void* user_data) -> jvmtiIterationControl {
422*795d594fSAndroid Build Coastguard Worker     *reinterpret_cast<jint*>(user_data) += 1;
423*795d594fSAndroid Build Coastguard Worker     return JVMTI_ITERATION_CONTINUE;
424*795d594fSAndroid Build Coastguard Worker   };
425*795d594fSAndroid Build Coastguard Worker   JvmtiErrorToException(env,
426*795d594fSAndroid Build Coastguard Worker                         jvmti_env,
427*795d594fSAndroid Build Coastguard Worker                         jvmti_env->IterateOverInstancesOfClass(target,
428*795d594fSAndroid Build Coastguard Worker                                                                JVMTI_HEAP_OBJECT_EITHER,
429*795d594fSAndroid Build Coastguard Worker                                                                count_func,
430*795d594fSAndroid Build Coastguard Worker                                                                &cnt));
431*795d594fSAndroid Build Coastguard Worker   return cnt;
432*795d594fSAndroid Build Coastguard Worker }
433*795d594fSAndroid Build Coastguard Worker 
434*795d594fSAndroid Build Coastguard Worker }  // namespace Test906IterateHeap
435*795d594fSAndroid Build Coastguard Worker }  // namespace art
436