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