1 /*
2  * Copyright (C) 2016 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 "ti_heap.h"
18 
19 #include "art_field-inl.h"
20 #include "art_jvmti.h"
21 #include "base/macros.h"
22 #include "base/mutex.h"
23 #include "class_linker.h"
24 #include "gc/heap.h"
25 #include "gc_root-inl.h"
26 #include "jni_env_ext.h"
27 #include "jni_internal.h"
28 #include "jvmti_weak_table-inl.h"
29 #include "mirror/class.h"
30 #include "mirror/object-inl.h"
31 #include "mirror/object_array-inl.h"
32 #include "object_callbacks.h"
33 #include "object_tagging.h"
34 #include "obj_ptr-inl.h"
35 #include "primitive.h"
36 #include "runtime.h"
37 #include "scoped_thread_state_change-inl.h"
38 #include "thread-inl.h"
39 #include "thread_list.h"
40 
41 namespace openjdkjvmti {
42 
43 namespace {
44 
45 struct IndexCache {
46   // The number of interface fields implemented by the class. This is a prefix to all assigned
47   // field indices.
48   size_t interface_fields;
49 
50   // It would be nice to also cache the following, but it is complicated to wire up into the
51   // generic visit:
52   // The number of fields in interfaces and superclasses. This is the first index assigned to
53   // fields of the class.
54   // size_t superclass_fields;
55 };
56 using IndexCachingTable = JvmtiWeakTable<IndexCache>;
57 
58 static IndexCachingTable gIndexCachingTable;
59 
60 // Report the contents of a string, if a callback is set.
ReportString(art::ObjPtr<art::mirror::Object> obj,jvmtiEnv * env,ObjectTagTable * tag_table,const jvmtiHeapCallbacks * cb,const void * user_data)61 jint ReportString(art::ObjPtr<art::mirror::Object> obj,
62                   jvmtiEnv* env,
63                   ObjectTagTable* tag_table,
64                   const jvmtiHeapCallbacks* cb,
65                   const void* user_data) REQUIRES_SHARED(art::Locks::mutator_lock_) {
66   if (UNLIKELY(cb->string_primitive_value_callback != nullptr) && obj->IsString()) {
67     art::ObjPtr<art::mirror::String> str = obj->AsString();
68     int32_t string_length = str->GetLength();
69     JvmtiUniquePtr<uint16_t[]> data;
70 
71     if (string_length > 0) {
72       jvmtiError alloc_error;
73       data = AllocJvmtiUniquePtr<uint16_t[]>(env, string_length, &alloc_error);
74       if (data == nullptr) {
75         // TODO: Not really sure what to do here. Should we abort the iteration and go all the way
76         //       back? For now just warn.
77         LOG(WARNING) << "Unable to allocate buffer for string reporting! Silently dropping value."
78                      << " >" << str->ToModifiedUtf8() << "<";
79         return 0;
80       }
81 
82       if (str->IsCompressed()) {
83         uint8_t* compressed_data = str->GetValueCompressed();
84         for (int32_t i = 0; i != string_length; ++i) {
85           data[i] = compressed_data[i];
86         }
87       } else {
88         // Can copy directly.
89         memcpy(data.get(), str->GetValue(), string_length * sizeof(uint16_t));
90       }
91     }
92 
93     const jlong class_tag = tag_table->GetTagOrZero(obj->GetClass());
94     jlong string_tag = tag_table->GetTagOrZero(obj.Ptr());
95     const jlong saved_string_tag = string_tag;
96 
97     jint result = cb->string_primitive_value_callback(class_tag,
98                                                       obj->SizeOf(),
99                                                       &string_tag,
100                                                       data.get(),
101                                                       string_length,
102                                                       const_cast<void*>(user_data));
103     if (string_tag != saved_string_tag) {
104       tag_table->Set(obj.Ptr(), string_tag);
105     }
106 
107     return result;
108   }
109   return 0;
110 }
111 
112 // Report the contents of a primitive array, if a callback is set.
ReportPrimitiveArray(art::ObjPtr<art::mirror::Object> obj,jvmtiEnv * env,ObjectTagTable * tag_table,const jvmtiHeapCallbacks * cb,const void * user_data)113 jint ReportPrimitiveArray(art::ObjPtr<art::mirror::Object> obj,
114                           jvmtiEnv* env,
115                           ObjectTagTable* tag_table,
116                           const jvmtiHeapCallbacks* cb,
117                           const void* user_data) REQUIRES_SHARED(art::Locks::mutator_lock_) {
118   if (UNLIKELY(cb->array_primitive_value_callback != nullptr) &&
119       obj->IsArrayInstance() &&
120       !obj->IsObjectArray()) {
121     art::ObjPtr<art::mirror::Array> array = obj->AsArray();
122     int32_t array_length = array->GetLength();
123     size_t component_size = array->GetClass()->GetComponentSize();
124     art::Primitive::Type art_prim_type = array->GetClass()->GetComponentType()->GetPrimitiveType();
125     jvmtiPrimitiveType prim_type =
126         static_cast<jvmtiPrimitiveType>(art::Primitive::Descriptor(art_prim_type)[0]);
127     DCHECK(prim_type == JVMTI_PRIMITIVE_TYPE_BOOLEAN ||
128            prim_type == JVMTI_PRIMITIVE_TYPE_BYTE ||
129            prim_type == JVMTI_PRIMITIVE_TYPE_CHAR ||
130            prim_type == JVMTI_PRIMITIVE_TYPE_SHORT ||
131            prim_type == JVMTI_PRIMITIVE_TYPE_INT ||
132            prim_type == JVMTI_PRIMITIVE_TYPE_LONG ||
133            prim_type == JVMTI_PRIMITIVE_TYPE_FLOAT ||
134            prim_type == JVMTI_PRIMITIVE_TYPE_DOUBLE);
135 
136     const jlong class_tag = tag_table->GetTagOrZero(obj->GetClass());
137     jlong array_tag = tag_table->GetTagOrZero(obj.Ptr());
138     const jlong saved_array_tag = array_tag;
139 
140     jint result;
141     if (array_length == 0) {
142       result = cb->array_primitive_value_callback(class_tag,
143                                                   obj->SizeOf(),
144                                                   &array_tag,
145                                                   0,
146                                                   prim_type,
147                                                   nullptr,
148                                                   const_cast<void*>(user_data));
149     } else {
150       jvmtiError alloc_error;
151       JvmtiUniquePtr<char[]> data = AllocJvmtiUniquePtr<char[]>(env,
152                                                                 array_length * component_size,
153                                                                 &alloc_error);
154       if (data == nullptr) {
155         // TODO: Not really sure what to do here. Should we abort the iteration and go all the way
156         //       back? For now just warn.
157         LOG(WARNING) << "Unable to allocate buffer for array reporting! Silently dropping value.";
158         return 0;
159       }
160 
161       memcpy(data.get(), array->GetRawData(component_size, 0), array_length * component_size);
162 
163       result = cb->array_primitive_value_callback(class_tag,
164                                                   obj->SizeOf(),
165                                                   &array_tag,
166                                                   array_length,
167                                                   prim_type,
168                                                   data.get(),
169                                                   const_cast<void*>(user_data));
170     }
171 
172     if (array_tag != saved_array_tag) {
173       tag_table->Set(obj.Ptr(), array_tag);
174     }
175 
176     return result;
177   }
178   return 0;
179 }
180 
181 template <typename UserData>
VisitorFalse(art::ObjPtr<art::mirror::Object> obj ATTRIBUTE_UNUSED,art::ObjPtr<art::mirror::Class> klass ATTRIBUTE_UNUSED,art::ArtField & field ATTRIBUTE_UNUSED,size_t field_index ATTRIBUTE_UNUSED,UserData * user_data ATTRIBUTE_UNUSED)182 bool VisitorFalse(art::ObjPtr<art::mirror::Object> obj ATTRIBUTE_UNUSED,
183                   art::ObjPtr<art::mirror::Class> klass ATTRIBUTE_UNUSED,
184                   art::ArtField& field ATTRIBUTE_UNUSED,
185                   size_t field_index ATTRIBUTE_UNUSED,
186                   UserData* user_data ATTRIBUTE_UNUSED) {
187   return false;
188 }
189 
190 template <typename UserData, bool kCallVisitorOnRecursion>
191 class FieldVisitor {
192  public:
193   // Report the contents of a primitive fields of the given object, if a callback is set.
194   template <typename StaticPrimitiveVisitor,
195             typename StaticReferenceVisitor,
196             typename InstancePrimitiveVisitor,
197             typename InstanceReferenceVisitor>
ReportFields(art::ObjPtr<art::mirror::Object> obj,UserData * user_data,StaticPrimitiveVisitor & static_prim_visitor,StaticReferenceVisitor & static_ref_visitor,InstancePrimitiveVisitor & instance_prim_visitor,InstanceReferenceVisitor & instance_ref_visitor)198   static bool ReportFields(art::ObjPtr<art::mirror::Object> obj,
199                            UserData* user_data,
200                            StaticPrimitiveVisitor& static_prim_visitor,
201                            StaticReferenceVisitor& static_ref_visitor,
202                            InstancePrimitiveVisitor& instance_prim_visitor,
203                            InstanceReferenceVisitor& instance_ref_visitor)
204       REQUIRES_SHARED(art::Locks::mutator_lock_) {
205     FieldVisitor fv(user_data);
206 
207     if (obj->IsClass()) {
208       // When visiting a class, we only visit the static fields of the given class. No field of
209       // superclasses is visited.
210       art::ObjPtr<art::mirror::Class> klass = obj->AsClass();
211       // Only report fields on resolved classes. We need valid field data.
212       if (!klass->IsResolved()) {
213         return false;
214       }
215       return fv.ReportFieldsImpl(nullptr,
216                                  obj->AsClass(),
217                                  obj->AsClass()->IsInterface(),
218                                  static_prim_visitor,
219                                  static_ref_visitor,
220                                  instance_prim_visitor,
221                                  instance_ref_visitor);
222     } else {
223       // See comment above. Just double-checking here, but an instance *should* mean the class was
224       // resolved.
225       DCHECK(obj->GetClass()->IsResolved() || obj->GetClass()->IsErroneousResolved());
226       return fv.ReportFieldsImpl(obj,
227                                  obj->GetClass(),
228                                  false,
229                                  static_prim_visitor,
230                                  static_ref_visitor,
231                                  instance_prim_visitor,
232                                  instance_ref_visitor);
233     }
234   }
235 
236  private:
FieldVisitor(UserData * user_data)237   explicit FieldVisitor(UserData* user_data) : user_data_(user_data) {}
238 
239   // Report the contents of fields of the given object. If obj is null, report the static fields,
240   // otherwise the instance fields.
241   template <typename StaticPrimitiveVisitor,
242             typename StaticReferenceVisitor,
243             typename InstancePrimitiveVisitor,
244             typename InstanceReferenceVisitor>
ReportFieldsImpl(art::ObjPtr<art::mirror::Object> obj,art::ObjPtr<art::mirror::Class> klass,bool skip_java_lang_object,StaticPrimitiveVisitor & static_prim_visitor,StaticReferenceVisitor & static_ref_visitor,InstancePrimitiveVisitor & instance_prim_visitor,InstanceReferenceVisitor & instance_ref_visitor)245   bool ReportFieldsImpl(art::ObjPtr<art::mirror::Object> obj,
246                         art::ObjPtr<art::mirror::Class> klass,
247                         bool skip_java_lang_object,
248                         StaticPrimitiveVisitor& static_prim_visitor,
249                         StaticReferenceVisitor& static_ref_visitor,
250                         InstancePrimitiveVisitor& instance_prim_visitor,
251                         InstanceReferenceVisitor& instance_ref_visitor)
252       REQUIRES_SHARED(art::Locks::mutator_lock_) {
253     // Compute the offset of field indices.
254     size_t interface_field_count = CountInterfaceFields(klass);
255 
256     size_t tmp;
257     bool aborted = ReportFieldsRecursive(obj,
258                                          klass,
259                                          interface_field_count,
260                                          skip_java_lang_object,
261                                          static_prim_visitor,
262                                          static_ref_visitor,
263                                          instance_prim_visitor,
264                                          instance_ref_visitor,
265                                          &tmp);
266     return aborted;
267   }
268 
269   // Visit primitive fields in an object (instance). Return true if the visit was aborted.
270   template <typename StaticPrimitiveVisitor,
271             typename StaticReferenceVisitor,
272             typename InstancePrimitiveVisitor,
273             typename InstanceReferenceVisitor>
ReportFieldsRecursive(art::ObjPtr<art::mirror::Object> obj,art::ObjPtr<art::mirror::Class> klass,size_t interface_fields,bool skip_java_lang_object,StaticPrimitiveVisitor & static_prim_visitor,StaticReferenceVisitor & static_ref_visitor,InstancePrimitiveVisitor & instance_prim_visitor,InstanceReferenceVisitor & instance_ref_visitor,size_t * field_index_out)274   bool ReportFieldsRecursive(art::ObjPtr<art::mirror::Object> obj,
275                              art::ObjPtr<art::mirror::Class> klass,
276                              size_t interface_fields,
277                              bool skip_java_lang_object,
278                              StaticPrimitiveVisitor& static_prim_visitor,
279                              StaticReferenceVisitor& static_ref_visitor,
280                              InstancePrimitiveVisitor& instance_prim_visitor,
281                              InstanceReferenceVisitor& instance_ref_visitor,
282                              size_t* field_index_out)
283       REQUIRES_SHARED(art::Locks::mutator_lock_) {
284     DCHECK(klass != nullptr);
285     size_t field_index;
286     if (klass->GetSuperClass() == nullptr) {
287       // j.l.Object. Start with the fields from interfaces.
288       field_index = interface_fields;
289       if (skip_java_lang_object) {
290         *field_index_out = field_index;
291         return false;
292       }
293     } else {
294       // Report superclass fields.
295       if (kCallVisitorOnRecursion) {
296         if (ReportFieldsRecursive(obj,
297                                   klass->GetSuperClass(),
298                                   interface_fields,
299                                   skip_java_lang_object,
300                                   static_prim_visitor,
301                                   static_ref_visitor,
302                                   instance_prim_visitor,
303                                   instance_ref_visitor,
304                                   &field_index)) {
305           return true;
306         }
307       } else {
308         // Still call, but with empty visitor. This is required for correct counting.
309         ReportFieldsRecursive(obj,
310                               klass->GetSuperClass(),
311                               interface_fields,
312                               skip_java_lang_object,
313                               VisitorFalse<UserData>,
314                               VisitorFalse<UserData>,
315                               VisitorFalse<UserData>,
316                               VisitorFalse<UserData>,
317                               &field_index);
318       }
319     }
320 
321     // Now visit fields for the current klass.
322 
323     for (auto& static_field : klass->GetSFields()) {
324       if (static_field.IsPrimitiveType()) {
325         if (static_prim_visitor(obj,
326                                 klass,
327                                 static_field,
328                                 field_index,
329                                 user_data_)) {
330           return true;
331         }
332       } else {
333         if (static_ref_visitor(obj,
334                                klass,
335                                static_field,
336                                field_index,
337                                user_data_)) {
338           return true;
339         }
340       }
341       field_index++;
342     }
343 
344     for (auto& instance_field : klass->GetIFields()) {
345       if (instance_field.IsPrimitiveType()) {
346         if (instance_prim_visitor(obj,
347                                   klass,
348                                   instance_field,
349                                   field_index,
350                                   user_data_)) {
351           return true;
352         }
353       } else {
354         if (instance_ref_visitor(obj,
355                                  klass,
356                                  instance_field,
357                                  field_index,
358                                  user_data_)) {
359           return true;
360         }
361       }
362       field_index++;
363     }
364 
365     *field_index_out = field_index;
366     return false;
367   }
368 
369   // Implements a visit of the implemented interfaces of a given class.
370   template <typename T>
371   struct RecursiveInterfaceVisit {
VisitStaticopenjdkjvmti::__anon85ffd7fa0111::FieldVisitor::RecursiveInterfaceVisit372     static void VisitStatic(art::Thread* self, art::ObjPtr<art::mirror::Class> klass, T& visitor)
373         REQUIRES_SHARED(art::Locks::mutator_lock_) {
374       RecursiveInterfaceVisit rv;
375       rv.Visit(self, klass, visitor);
376     }
377 
Visitopenjdkjvmti::__anon85ffd7fa0111::FieldVisitor::RecursiveInterfaceVisit378     void Visit(art::Thread* self, art::ObjPtr<art::mirror::Class> klass, T& visitor)
379         REQUIRES_SHARED(art::Locks::mutator_lock_) {
380       // First visit the parent, to get the order right.
381       // (We do this in preparation for actual visiting of interface fields.)
382       if (klass->GetSuperClass() != nullptr) {
383         Visit(self, klass->GetSuperClass(), visitor);
384       }
385       for (uint32_t i = 0; i != klass->NumDirectInterfaces(); ++i) {
386         art::ObjPtr<art::mirror::Class> inf_klass =
387             art::mirror::Class::GetDirectInterface(self, klass, i);
388         DCHECK(inf_klass != nullptr);
389         VisitInterface(self, inf_klass, visitor);
390       }
391     }
392 
VisitInterfaceopenjdkjvmti::__anon85ffd7fa0111::FieldVisitor::RecursiveInterfaceVisit393     void VisitInterface(art::Thread* self, art::ObjPtr<art::mirror::Class> inf_klass, T& visitor)
394         REQUIRES_SHARED(art::Locks::mutator_lock_) {
395       auto it = visited_interfaces.find(inf_klass.Ptr());
396       if (it != visited_interfaces.end()) {
397         return;
398       }
399       visited_interfaces.insert(inf_klass.Ptr());
400 
401       // Let the visitor know about this one. Note that this order is acceptable, as the ordering
402       // of these fields never matters for known visitors.
403       visitor(inf_klass);
404 
405       // Now visit the superinterfaces.
406       for (uint32_t i = 0; i != inf_klass->NumDirectInterfaces(); ++i) {
407         art::ObjPtr<art::mirror::Class> super_inf_klass =
408             art::mirror::Class::GetDirectInterface(self, inf_klass, i);
409         DCHECK(super_inf_klass != nullptr);
410         VisitInterface(self, super_inf_klass, visitor);
411       }
412     }
413 
414     std::unordered_set<art::mirror::Class*> visited_interfaces;
415   };
416 
417   // Counting interface fields. Note that we cannot use the interface table, as that only contains
418   // "non-marker" interfaces (= interfaces with methods).
CountInterfaceFields(art::ObjPtr<art::mirror::Class> klass)419   static size_t CountInterfaceFields(art::ObjPtr<art::mirror::Class> klass)
420       REQUIRES_SHARED(art::Locks::mutator_lock_) {
421     // Do we have a cached value?
422     IndexCache tmp;
423     if (gIndexCachingTable.GetTag(klass.Ptr(), &tmp)) {
424       return tmp.interface_fields;
425     }
426 
427     size_t count = 0;
428     auto visitor = [&count](art::ObjPtr<art::mirror::Class> inf_klass)
429         REQUIRES_SHARED(art::Locks::mutator_lock_) {
430       DCHECK(inf_klass->IsInterface());
431       DCHECK_EQ(0u, inf_klass->NumInstanceFields());
432       count += inf_klass->NumStaticFields();
433     };
434     RecursiveInterfaceVisit<decltype(visitor)>::VisitStatic(art::Thread::Current(), klass, visitor);
435 
436     // Store this into the cache.
437     tmp.interface_fields = count;
438     gIndexCachingTable.Set(klass.Ptr(), tmp);
439 
440     return count;
441   }
442 
443   UserData* user_data_;
444 };
445 
446 // Debug helper. Prints the structure of an object.
447 template <bool kStatic, bool kRef>
448 struct DumpVisitor {
Callbackopenjdkjvmti::__anon85ffd7fa0111::DumpVisitor449   static bool Callback(art::ObjPtr<art::mirror::Object> obj ATTRIBUTE_UNUSED,
450                        art::ObjPtr<art::mirror::Class> klass ATTRIBUTE_UNUSED,
451                        art::ArtField& field,
452                        size_t field_index,
453                        void* user_data ATTRIBUTE_UNUSED)
454       REQUIRES_SHARED(art::Locks::mutator_lock_) {
455     LOG(ERROR) << (kStatic ? "static " : "instance ")
456                << (kRef ? "ref " : "primitive ")
457                << field.PrettyField()
458                << " @ "
459                << field_index;
460     return false;
461   }
462 };
463 ATTRIBUTE_UNUSED
DumpObjectFields(art::ObjPtr<art::mirror::Object> obj)464 void DumpObjectFields(art::ObjPtr<art::mirror::Object> obj)
465     REQUIRES_SHARED(art::Locks::mutator_lock_) {
466   if (obj->IsClass()) {
467     FieldVisitor<void, false>:: ReportFields(obj,
468                                              nullptr,
469                                              DumpVisitor<true, false>::Callback,
470                                              DumpVisitor<true, true>::Callback,
471                                              DumpVisitor<false, false>::Callback,
472                                              DumpVisitor<false, true>::Callback);
473   } else {
474     FieldVisitor<void, true>::ReportFields(obj,
475                                            nullptr,
476                                            DumpVisitor<true, false>::Callback,
477                                            DumpVisitor<true, true>::Callback,
478                                            DumpVisitor<false, false>::Callback,
479                                            DumpVisitor<false, true>::Callback);
480   }
481 }
482 
483 class ReportPrimitiveField {
484  public:
Report(art::ObjPtr<art::mirror::Object> obj,ObjectTagTable * tag_table,const jvmtiHeapCallbacks * cb,const void * user_data)485   static bool Report(art::ObjPtr<art::mirror::Object> obj,
486                      ObjectTagTable* tag_table,
487                      const jvmtiHeapCallbacks* cb,
488                      const void* user_data)
489       REQUIRES_SHARED(art::Locks::mutator_lock_) {
490     if (UNLIKELY(cb->primitive_field_callback != nullptr)) {
491       jlong class_tag = tag_table->GetTagOrZero(obj->GetClass());
492       ReportPrimitiveField rpf(tag_table, class_tag, cb, user_data);
493       if (obj->IsClass()) {
494         return FieldVisitor<ReportPrimitiveField, false>::ReportFields(
495             obj,
496             &rpf,
497             ReportPrimitiveFieldCallback<true>,
498             VisitorFalse<ReportPrimitiveField>,
499             VisitorFalse<ReportPrimitiveField>,
500             VisitorFalse<ReportPrimitiveField>);
501       } else {
502         return FieldVisitor<ReportPrimitiveField, true>::ReportFields(
503             obj,
504             &rpf,
505             VisitorFalse<ReportPrimitiveField>,
506             VisitorFalse<ReportPrimitiveField>,
507             ReportPrimitiveFieldCallback<false>,
508             VisitorFalse<ReportPrimitiveField>);
509       }
510     }
511     return false;
512   }
513 
514 
515  private:
ReportPrimitiveField(ObjectTagTable * tag_table,jlong class_tag,const jvmtiHeapCallbacks * cb,const void * user_data)516   ReportPrimitiveField(ObjectTagTable* tag_table,
517                        jlong class_tag,
518                        const jvmtiHeapCallbacks* cb,
519                        const void* user_data)
520       : tag_table_(tag_table), class_tag_(class_tag), cb_(cb), user_data_(user_data) {}
521 
522   template <bool kReportStatic>
ReportPrimitiveFieldCallback(art::ObjPtr<art::mirror::Object> obj,art::ObjPtr<art::mirror::Class> klass,art::ArtField & field,size_t field_index,ReportPrimitiveField * user_data)523   static bool ReportPrimitiveFieldCallback(art::ObjPtr<art::mirror::Object> obj,
524                                            art::ObjPtr<art::mirror::Class> klass,
525                                            art::ArtField& field,
526                                            size_t field_index,
527                                            ReportPrimitiveField* user_data)
528       REQUIRES_SHARED(art::Locks::mutator_lock_) {
529     art::Primitive::Type art_prim_type = field.GetTypeAsPrimitiveType();
530     jvmtiPrimitiveType prim_type =
531         static_cast<jvmtiPrimitiveType>(art::Primitive::Descriptor(art_prim_type)[0]);
532     DCHECK(prim_type == JVMTI_PRIMITIVE_TYPE_BOOLEAN ||
533            prim_type == JVMTI_PRIMITIVE_TYPE_BYTE ||
534            prim_type == JVMTI_PRIMITIVE_TYPE_CHAR ||
535            prim_type == JVMTI_PRIMITIVE_TYPE_SHORT ||
536            prim_type == JVMTI_PRIMITIVE_TYPE_INT ||
537            prim_type == JVMTI_PRIMITIVE_TYPE_LONG ||
538            prim_type == JVMTI_PRIMITIVE_TYPE_FLOAT ||
539            prim_type == JVMTI_PRIMITIVE_TYPE_DOUBLE);
540     jvmtiHeapReferenceInfo info;
541     info.field.index = field_index;
542 
543     jvalue value;
544     memset(&value, 0, sizeof(jvalue));
545     art::ObjPtr<art::mirror::Object> src = kReportStatic ? klass : obj;
546     switch (art_prim_type) {
547       case art::Primitive::Type::kPrimBoolean:
548         value.z = field.GetBoolean(src) == 0 ? JNI_FALSE : JNI_TRUE;
549         break;
550       case art::Primitive::Type::kPrimByte:
551         value.b = field.GetByte(src);
552         break;
553       case art::Primitive::Type::kPrimChar:
554         value.c = field.GetChar(src);
555         break;
556       case art::Primitive::Type::kPrimShort:
557         value.s = field.GetShort(src);
558         break;
559       case art::Primitive::Type::kPrimInt:
560         value.i = field.GetInt(src);
561         break;
562       case art::Primitive::Type::kPrimLong:
563         value.j = field.GetLong(src);
564         break;
565       case art::Primitive::Type::kPrimFloat:
566         value.f = field.GetFloat(src);
567         break;
568       case art::Primitive::Type::kPrimDouble:
569         value.d = field.GetDouble(src);
570         break;
571       case art::Primitive::Type::kPrimVoid:
572       case art::Primitive::Type::kPrimNot: {
573         LOG(FATAL) << "Should not reach here";
574         UNREACHABLE();
575       }
576     }
577 
578     jlong obj_tag = user_data->tag_table_->GetTagOrZero(src.Ptr());
579     const jlong saved_obj_tag = obj_tag;
580 
581     jint ret = user_data->cb_->primitive_field_callback(kReportStatic
582                                                             ? JVMTI_HEAP_REFERENCE_STATIC_FIELD
583                                                             : JVMTI_HEAP_REFERENCE_FIELD,
584                                                         &info,
585                                                         user_data->class_tag_,
586                                                         &obj_tag,
587                                                         value,
588                                                         prim_type,
589                                                         const_cast<void*>(user_data->user_data_));
590 
591     if (saved_obj_tag != obj_tag) {
592       user_data->tag_table_->Set(src.Ptr(), obj_tag);
593     }
594 
595     if ((ret & JVMTI_VISIT_ABORT) != 0) {
596       return true;
597     }
598 
599     return false;
600   }
601 
602   ObjectTagTable* tag_table_;
603   jlong class_tag_;
604   const jvmtiHeapCallbacks* cb_;
605   const void* user_data_;
606 };
607 
608 struct HeapFilter {
HeapFilteropenjdkjvmti::__anon85ffd7fa0111::HeapFilter609   explicit HeapFilter(jint heap_filter)
610       : filter_out_tagged((heap_filter & JVMTI_HEAP_FILTER_TAGGED) != 0),
611         filter_out_untagged((heap_filter & JVMTI_HEAP_FILTER_UNTAGGED) != 0),
612         filter_out_class_tagged((heap_filter & JVMTI_HEAP_FILTER_CLASS_TAGGED) != 0),
613         filter_out_class_untagged((heap_filter & JVMTI_HEAP_FILTER_CLASS_UNTAGGED) != 0),
614         any_filter(filter_out_tagged ||
615                    filter_out_untagged ||
616                    filter_out_class_tagged ||
617                    filter_out_class_untagged) {
618   }
619 
ShouldReportByHeapFilteropenjdkjvmti::__anon85ffd7fa0111::HeapFilter620   bool ShouldReportByHeapFilter(jlong tag, jlong class_tag) const {
621     if (!any_filter) {
622       return true;
623     }
624 
625     if ((tag == 0 && filter_out_untagged) || (tag != 0 && filter_out_tagged)) {
626       return false;
627     }
628 
629     if ((class_tag == 0 && filter_out_class_untagged) ||
630         (class_tag != 0 && filter_out_class_tagged)) {
631       return false;
632     }
633 
634     return true;
635   }
636 
637   const bool filter_out_tagged;
638   const bool filter_out_untagged;
639   const bool filter_out_class_tagged;
640   const bool filter_out_class_untagged;
641   const bool any_filter;
642 };
643 
644 }  // namespace
645 
Register()646 void HeapUtil::Register() {
647   art::Runtime::Current()->AddSystemWeakHolder(&gIndexCachingTable);
648 }
649 
Unregister()650 void HeapUtil::Unregister() {
651   art::Runtime::Current()->RemoveSystemWeakHolder(&gIndexCachingTable);
652 }
653 
654 template <typename Callback>
655 struct IterateThroughHeapData {
IterateThroughHeapDataopenjdkjvmti::IterateThroughHeapData656   IterateThroughHeapData(Callback _cb,
657                          ObjectTagTable* _tag_table,
658                          jvmtiEnv* _env,
659                          art::ObjPtr<art::mirror::Class> klass,
660                          jint _heap_filter,
661                          const jvmtiHeapCallbacks* _callbacks,
662                          const void* _user_data)
663       : cb(_cb),
664         tag_table(_tag_table),
665         heap_filter(_heap_filter),
666         filter_klass(klass),
667         env(_env),
668         callbacks(_callbacks),
669         user_data(_user_data),
670         stop_reports(false) {
671   }
672 
ObjectCallbackopenjdkjvmti::IterateThroughHeapData673   static void ObjectCallback(art::mirror::Object* obj, void* arg)
674       REQUIRES_SHARED(art::Locks::mutator_lock_) {
675     IterateThroughHeapData* ithd = reinterpret_cast<IterateThroughHeapData*>(arg);
676     ithd->ObjectCallback(obj);
677   }
678 
ObjectCallbackopenjdkjvmti::IterateThroughHeapData679   void ObjectCallback(art::mirror::Object* obj)
680       REQUIRES_SHARED(art::Locks::mutator_lock_) {
681     // Early return, as we can't really stop visiting.
682     if (stop_reports) {
683       return;
684     }
685 
686     art::ScopedAssertNoThreadSuspension no_suspension("IterateThroughHeapCallback");
687 
688     jlong tag = 0;
689     tag_table->GetTag(obj, &tag);
690 
691     jlong class_tag = 0;
692     art::ObjPtr<art::mirror::Class> klass = obj->GetClass();
693     tag_table->GetTag(klass.Ptr(), &class_tag);
694     // For simplicity, even if we find a tag = 0, assume 0 = not tagged.
695 
696     if (!heap_filter.ShouldReportByHeapFilter(tag, class_tag)) {
697       return;
698     }
699 
700     if (filter_klass != nullptr) {
701       if (filter_klass != klass) {
702         return;
703       }
704     }
705 
706     jlong size = obj->SizeOf();
707 
708     jint length = -1;
709     if (obj->IsArrayInstance()) {
710       length = obj->AsArray()->GetLength();
711     }
712 
713     jlong saved_tag = tag;
714     jint ret = cb(obj, callbacks, class_tag, size, &tag, length, const_cast<void*>(user_data));
715 
716     if (tag != saved_tag) {
717       tag_table->Set(obj, tag);
718     }
719 
720     stop_reports = (ret & JVMTI_VISIT_ABORT) != 0;
721 
722     if (!stop_reports) {
723       jint string_ret = ReportString(obj, env, tag_table, callbacks, user_data);
724       stop_reports = (string_ret & JVMTI_VISIT_ABORT) != 0;
725     }
726 
727     if (!stop_reports) {
728       jint array_ret = ReportPrimitiveArray(obj, env, tag_table, callbacks, user_data);
729       stop_reports = (array_ret & JVMTI_VISIT_ABORT) != 0;
730     }
731 
732     if (!stop_reports) {
733       stop_reports = ReportPrimitiveField::Report(obj, tag_table, callbacks, user_data);
734     }
735   }
736 
737   Callback cb;
738   ObjectTagTable* tag_table;
739   const HeapFilter heap_filter;
740   art::ObjPtr<art::mirror::Class> filter_klass;
741   jvmtiEnv* env;
742   const jvmtiHeapCallbacks* callbacks;
743   const void* user_data;
744 
745   bool stop_reports;
746 };
747 
748 template <typename T>
DoIterateThroughHeap(T fn,jvmtiEnv * env,ObjectTagTable * tag_table,jint heap_filter,jclass klass,const jvmtiHeapCallbacks * callbacks,const void * user_data)749 static jvmtiError DoIterateThroughHeap(T fn,
750                                        jvmtiEnv* env,
751                                        ObjectTagTable* tag_table,
752                                        jint heap_filter,
753                                        jclass klass,
754                                        const jvmtiHeapCallbacks* callbacks,
755                                        const void* user_data) {
756   if (callbacks == nullptr) {
757     return ERR(NULL_POINTER);
758   }
759 
760   art::Thread* self = art::Thread::Current();
761   art::ScopedObjectAccess soa(self);      // Now we know we have the shared lock.
762 
763   using Iterator = IterateThroughHeapData<T>;
764   Iterator ithd(fn,
765                 tag_table,
766                 env,
767                 soa.Decode<art::mirror::Class>(klass),
768                 heap_filter,
769                 callbacks,
770                 user_data);
771 
772   art::Runtime::Current()->GetHeap()->VisitObjects(Iterator::ObjectCallback, &ithd);
773 
774   return ERR(NONE);
775 }
776 
IterateThroughHeap(jvmtiEnv * env,jint heap_filter,jclass klass,const jvmtiHeapCallbacks * callbacks,const void * user_data)777 jvmtiError HeapUtil::IterateThroughHeap(jvmtiEnv* env,
778                                         jint heap_filter,
779                                         jclass klass,
780                                         const jvmtiHeapCallbacks* callbacks,
781                                         const void* user_data) {
782   auto JvmtiIterateHeap = [](art::mirror::Object* obj ATTRIBUTE_UNUSED,
783                              const jvmtiHeapCallbacks* cb_callbacks,
784                              jlong class_tag,
785                              jlong size,
786                              jlong* tag,
787                              jint length,
788                              void* cb_user_data)
789       REQUIRES_SHARED(art::Locks::mutator_lock_) {
790     return cb_callbacks->heap_iteration_callback(class_tag,
791                                                  size,
792                                                  tag,
793                                                  length,
794                                                  cb_user_data);
795   };
796   return DoIterateThroughHeap(JvmtiIterateHeap,
797                               env,
798                               ArtJvmTiEnv::AsArtJvmTiEnv(env)->object_tag_table.get(),
799                               heap_filter,
800                               klass,
801                               callbacks,
802                               user_data);
803 }
804 
805 class FollowReferencesHelper FINAL {
806  public:
FollowReferencesHelper(HeapUtil * h,jvmtiEnv * jvmti_env,art::ObjPtr<art::mirror::Object> initial_object,const jvmtiHeapCallbacks * callbacks,art::ObjPtr<art::mirror::Class> class_filter,jint heap_filter,const void * user_data)807   FollowReferencesHelper(HeapUtil* h,
808                          jvmtiEnv* jvmti_env,
809                          art::ObjPtr<art::mirror::Object> initial_object,
810                          const jvmtiHeapCallbacks* callbacks,
811                          art::ObjPtr<art::mirror::Class> class_filter,
812                          jint heap_filter,
813                          const void* user_data)
814       : env(jvmti_env),
815         tag_table_(h->GetTags()),
816         initial_object_(initial_object),
817         callbacks_(callbacks),
818         class_filter_(class_filter),
819         heap_filter_(heap_filter),
820         user_data_(user_data),
821         start_(0),
822         stop_reports_(false) {
823   }
824 
Init()825   void Init()
826       REQUIRES_SHARED(art::Locks::mutator_lock_)
827       REQUIRES(!*tag_table_->GetAllowDisallowLock()) {
828     if (initial_object_.IsNull()) {
829       CollectAndReportRootsVisitor carrv(this, tag_table_, &worklist_, &visited_);
830 
831       // We need precise info (e.g., vregs).
832       constexpr art::VisitRootFlags kRootFlags = static_cast<art::VisitRootFlags>(
833           art::VisitRootFlags::kVisitRootFlagAllRoots | art::VisitRootFlags::kVisitRootFlagPrecise);
834       art::Runtime::Current()->VisitRoots(&carrv, kRootFlags);
835 
836       art::Runtime::Current()->VisitImageRoots(&carrv);
837       stop_reports_ = carrv.IsStopReports();
838 
839       if (stop_reports_) {
840         worklist_.clear();
841       }
842     } else {
843       visited_.insert(initial_object_.Ptr());
844       worklist_.push_back(initial_object_.Ptr());
845     }
846   }
847 
Work()848   void Work()
849       REQUIRES_SHARED(art::Locks::mutator_lock_)
850       REQUIRES(!*tag_table_->GetAllowDisallowLock()) {
851     // Currently implemented as a BFS. To lower overhead, we don't erase elements immediately
852     // from the head of the work list, instead postponing until there's a gap that's "large."
853     //
854     // Alternatively, we can implement a DFS and use the work list as a stack.
855     while (start_ < worklist_.size()) {
856       art::mirror::Object* cur_obj = worklist_[start_];
857       start_++;
858 
859       if (start_ >= kMaxStart) {
860         worklist_.erase(worklist_.begin(), worklist_.begin() + start_);
861         start_ = 0;
862       }
863 
864       VisitObject(cur_obj);
865 
866       if (stop_reports_) {
867         break;
868       }
869     }
870   }
871 
872  private:
873   class CollectAndReportRootsVisitor FINAL : public art::RootVisitor {
874    public:
CollectAndReportRootsVisitor(FollowReferencesHelper * helper,ObjectTagTable * tag_table,std::vector<art::mirror::Object * > * worklist,std::unordered_set<art::mirror::Object * > * visited)875     CollectAndReportRootsVisitor(FollowReferencesHelper* helper,
876                                  ObjectTagTable* tag_table,
877                                  std::vector<art::mirror::Object*>* worklist,
878                                  std::unordered_set<art::mirror::Object*>* visited)
879         : helper_(helper),
880           tag_table_(tag_table),
881           worklist_(worklist),
882           visited_(visited),
883           stop_reports_(false) {}
884 
VisitRoots(art::mirror::Object *** roots,size_t count,const art::RootInfo & info)885     void VisitRoots(art::mirror::Object*** roots, size_t count, const art::RootInfo& info)
886         OVERRIDE
887         REQUIRES_SHARED(art::Locks::mutator_lock_)
888         REQUIRES(!*helper_->tag_table_->GetAllowDisallowLock()) {
889       for (size_t i = 0; i != count; ++i) {
890         AddRoot(*roots[i], info);
891       }
892     }
893 
VisitRoots(art::mirror::CompressedReference<art::mirror::Object> ** roots,size_t count,const art::RootInfo & info)894     void VisitRoots(art::mirror::CompressedReference<art::mirror::Object>** roots,
895                     size_t count,
896                     const art::RootInfo& info)
897         OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_)
898         REQUIRES(!*helper_->tag_table_->GetAllowDisallowLock()) {
899       for (size_t i = 0; i != count; ++i) {
900         AddRoot(roots[i]->AsMirrorPtr(), info);
901       }
902     }
903 
IsStopReports()904     bool IsStopReports() {
905       return stop_reports_;
906     }
907 
908    private:
AddRoot(art::mirror::Object * root_obj,const art::RootInfo & info)909     void AddRoot(art::mirror::Object* root_obj, const art::RootInfo& info)
910         REQUIRES_SHARED(art::Locks::mutator_lock_)
911         REQUIRES(!*tag_table_->GetAllowDisallowLock()) {
912       if (stop_reports_) {
913         return;
914       }
915       bool add_to_worklist = ReportRoot(root_obj, info);
916       // We use visited_ to mark roots already so we do not need another set.
917       if (visited_->find(root_obj) == visited_->end()) {
918         if (add_to_worklist) {
919           visited_->insert(root_obj);
920           worklist_->push_back(root_obj);
921         }
922       }
923     }
924 
925     // Remove NO_THREAD_SAFETY_ANALYSIS once ASSERT_CAPABILITY works correctly.
FindThread(const art::RootInfo & info)926     art::Thread* FindThread(const art::RootInfo& info) NO_THREAD_SAFETY_ANALYSIS {
927       art::Locks::thread_list_lock_->AssertExclusiveHeld(art::Thread::Current());
928       return art::Runtime::Current()->GetThreadList()->FindThreadByThreadId(info.GetThreadId());
929     }
930 
GetReferenceKind(const art::RootInfo & info,jvmtiHeapReferenceInfo * ref_info)931     jvmtiHeapReferenceKind GetReferenceKind(const art::RootInfo& info,
932                                             jvmtiHeapReferenceInfo* ref_info)
933         REQUIRES_SHARED(art::Locks::mutator_lock_) {
934       // TODO: Fill in ref_info.
935       memset(ref_info, 0, sizeof(jvmtiHeapReferenceInfo));
936 
937       switch (info.GetType()) {
938         case art::RootType::kRootJNIGlobal:
939           return JVMTI_HEAP_REFERENCE_JNI_GLOBAL;
940 
941         case art::RootType::kRootJNILocal:
942         {
943           uint32_t thread_id = info.GetThreadId();
944           ref_info->jni_local.thread_id = thread_id;
945 
946           art::Thread* thread = FindThread(info);
947           if (thread != nullptr) {
948             art::mirror::Object* thread_obj;
949             if (thread->IsStillStarting()) {
950               thread_obj = nullptr;
951             } else {
952               thread_obj = thread->GetPeerFromOtherThread();
953             }
954             if (thread_obj != nullptr) {
955               ref_info->jni_local.thread_tag = tag_table_->GetTagOrZero(thread_obj);
956             }
957           }
958 
959           // TODO: We don't have this info.
960           if (thread != nullptr) {
961             ref_info->jni_local.depth = 0;
962             art::ArtMethod* method = thread->GetCurrentMethod(nullptr, false /* abort_on_error */);
963             if (method != nullptr) {
964               ref_info->jni_local.method = art::jni::EncodeArtMethod(method);
965             }
966           }
967 
968           return JVMTI_HEAP_REFERENCE_JNI_LOCAL;
969         }
970 
971         case art::RootType::kRootJavaFrame:
972         {
973           uint32_t thread_id = info.GetThreadId();
974           ref_info->stack_local.thread_id = thread_id;
975 
976           art::Thread* thread = FindThread(info);
977           if (thread != nullptr) {
978             art::mirror::Object* thread_obj;
979             if (thread->IsStillStarting()) {
980               thread_obj = nullptr;
981             } else {
982               thread_obj = thread->GetPeerFromOtherThread();
983             }
984             if (thread_obj != nullptr) {
985               ref_info->stack_local.thread_tag = tag_table_->GetTagOrZero(thread_obj);
986             }
987           }
988 
989           auto& java_info = static_cast<const art::JavaFrameRootInfo&>(info);
990           ref_info->stack_local.slot = static_cast<jint>(java_info.GetVReg());
991           const art::StackVisitor* visitor = java_info.GetVisitor();
992           ref_info->stack_local.location =
993               static_cast<jlocation>(visitor->GetDexPc(false /* abort_on_failure */));
994           ref_info->stack_local.depth = static_cast<jint>(visitor->GetFrameDepth());
995           art::ArtMethod* method = visitor->GetMethod();
996           if (method != nullptr) {
997             ref_info->stack_local.method = art::jni::EncodeArtMethod(method);
998           }
999 
1000           return JVMTI_HEAP_REFERENCE_STACK_LOCAL;
1001         }
1002 
1003         case art::RootType::kRootNativeStack:
1004         case art::RootType::kRootThreadBlock:
1005         case art::RootType::kRootThreadObject:
1006           return JVMTI_HEAP_REFERENCE_THREAD;
1007 
1008         case art::RootType::kRootStickyClass:
1009         case art::RootType::kRootInternedString:
1010           // Note: this isn't a root in the RI.
1011           return JVMTI_HEAP_REFERENCE_SYSTEM_CLASS;
1012 
1013         case art::RootType::kRootMonitorUsed:
1014         case art::RootType::kRootJNIMonitor:
1015           return JVMTI_HEAP_REFERENCE_MONITOR;
1016 
1017         case art::RootType::kRootFinalizing:
1018         case art::RootType::kRootDebugger:
1019         case art::RootType::kRootReferenceCleanup:
1020         case art::RootType::kRootVMInternal:
1021         case art::RootType::kRootUnknown:
1022           return JVMTI_HEAP_REFERENCE_OTHER;
1023       }
1024       LOG(FATAL) << "Unreachable";
1025       UNREACHABLE();
1026     }
1027 
ReportRoot(art::mirror::Object * root_obj,const art::RootInfo & info)1028     bool ReportRoot(art::mirror::Object* root_obj, const art::RootInfo& info)
1029         REQUIRES_SHARED(art::Locks::mutator_lock_)
1030         REQUIRES(!*tag_table_->GetAllowDisallowLock()) {
1031       jvmtiHeapReferenceInfo ref_info;
1032       jvmtiHeapReferenceKind kind = GetReferenceKind(info, &ref_info);
1033       jint result = helper_->ReportReference(kind, &ref_info, nullptr, root_obj);
1034       if ((result & JVMTI_VISIT_ABORT) != 0) {
1035         stop_reports_ = true;
1036       }
1037       return (result & JVMTI_VISIT_OBJECTS) != 0;
1038     }
1039 
1040    private:
1041     FollowReferencesHelper* helper_;
1042     ObjectTagTable* tag_table_;
1043     std::vector<art::mirror::Object*>* worklist_;
1044     std::unordered_set<art::mirror::Object*>* visited_;
1045     bool stop_reports_;
1046   };
1047 
VisitObject(art::mirror::Object * obj)1048   void VisitObject(art::mirror::Object* obj)
1049       REQUIRES_SHARED(art::Locks::mutator_lock_)
1050       REQUIRES(!*tag_table_->GetAllowDisallowLock()) {
1051     if (obj->IsClass()) {
1052       VisitClass(obj->AsClass());
1053       return;
1054     }
1055     if (obj->IsArrayInstance()) {
1056       VisitArray(obj);
1057       return;
1058     }
1059 
1060     // All instance fields.
1061     auto report_instance_field = [&](art::ObjPtr<art::mirror::Object> src,
1062                                      art::ObjPtr<art::mirror::Class> obj_klass ATTRIBUTE_UNUSED,
1063                                      art::ArtField& field,
1064                                      size_t field_index,
1065                                      void* user_data ATTRIBUTE_UNUSED)
1066         REQUIRES_SHARED(art::Locks::mutator_lock_)
1067         REQUIRES(!*tag_table_->GetAllowDisallowLock()) {
1068       art::ObjPtr<art::mirror::Object> field_value = field.GetObject(src);
1069       if (field_value != nullptr) {
1070         jvmtiHeapReferenceInfo reference_info;
1071         memset(&reference_info, 0, sizeof(reference_info));
1072 
1073         reference_info.field.index = field_index;
1074 
1075         jvmtiHeapReferenceKind kind =
1076             field.GetOffset().Int32Value() == art::mirror::Object::ClassOffset().Int32Value()
1077                 ? JVMTI_HEAP_REFERENCE_CLASS
1078                 : JVMTI_HEAP_REFERENCE_FIELD;
1079         const jvmtiHeapReferenceInfo* reference_info_ptr =
1080             kind == JVMTI_HEAP_REFERENCE_CLASS ? nullptr : &reference_info;
1081 
1082         return !ReportReferenceMaybeEnqueue(kind, reference_info_ptr, src.Ptr(), field_value.Ptr());
1083       }
1084       return false;
1085     };
1086     stop_reports_ = FieldVisitor<void, true>::ReportFields(obj,
1087                                                            nullptr,
1088                                                            VisitorFalse<void>,
1089                                                            VisitorFalse<void>,
1090                                                            VisitorFalse<void>,
1091                                                            report_instance_field);
1092     if (stop_reports_) {
1093       return;
1094     }
1095 
1096     jint string_ret = ReportString(obj, env, tag_table_, callbacks_, user_data_);
1097     stop_reports_ = (string_ret & JVMTI_VISIT_ABORT) != 0;
1098     if (stop_reports_) {
1099       return;
1100     }
1101 
1102     stop_reports_ = ReportPrimitiveField::Report(obj, tag_table_, callbacks_, user_data_);
1103   }
1104 
VisitArray(art::mirror::Object * array)1105   void VisitArray(art::mirror::Object* array)
1106       REQUIRES_SHARED(art::Locks::mutator_lock_)
1107       REQUIRES(!*tag_table_->GetAllowDisallowLock()) {
1108     stop_reports_ = !ReportReferenceMaybeEnqueue(JVMTI_HEAP_REFERENCE_CLASS,
1109                                                  nullptr,
1110                                                  array,
1111                                                  array->GetClass());
1112     if (stop_reports_) {
1113       return;
1114     }
1115 
1116     if (array->IsObjectArray()) {
1117       art::mirror::ObjectArray<art::mirror::Object>* obj_array =
1118           array->AsObjectArray<art::mirror::Object>();
1119       int32_t length = obj_array->GetLength();
1120       for (int32_t i = 0; i != length; ++i) {
1121         art::mirror::Object* elem = obj_array->GetWithoutChecks(i);
1122         if (elem != nullptr) {
1123           jvmtiHeapReferenceInfo reference_info;
1124           reference_info.array.index = i;
1125           stop_reports_ = !ReportReferenceMaybeEnqueue(JVMTI_HEAP_REFERENCE_ARRAY_ELEMENT,
1126                                                        &reference_info,
1127                                                        array,
1128                                                        elem);
1129           if (stop_reports_) {
1130             break;
1131           }
1132         }
1133       }
1134     } else {
1135       if (!stop_reports_) {
1136         jint array_ret = ReportPrimitiveArray(array, env, tag_table_, callbacks_, user_data_);
1137         stop_reports_ = (array_ret & JVMTI_VISIT_ABORT) != 0;
1138       }
1139     }
1140   }
1141 
VisitClass(art::mirror::Class * klass)1142   void VisitClass(art::mirror::Class* klass)
1143       REQUIRES_SHARED(art::Locks::mutator_lock_)
1144       REQUIRES(!*tag_table_->GetAllowDisallowLock()) {
1145     // TODO: Are erroneous classes reported? Are non-prepared ones? For now, just use resolved ones.
1146     if (!klass->IsResolved()) {
1147       return;
1148     }
1149 
1150     // Superclass.
1151     stop_reports_ = !ReportReferenceMaybeEnqueue(JVMTI_HEAP_REFERENCE_SUPERCLASS,
1152                                                  nullptr,
1153                                                  klass,
1154                                                  klass->GetSuperClass());
1155     if (stop_reports_) {
1156       return;
1157     }
1158 
1159     // Directly implemented or extended interfaces.
1160     art::Thread* self = art::Thread::Current();
1161     art::StackHandleScope<1> hs(self);
1162     art::Handle<art::mirror::Class> h_klass(hs.NewHandle<art::mirror::Class>(klass));
1163     for (size_t i = 0; i < h_klass->NumDirectInterfaces(); ++i) {
1164       art::ObjPtr<art::mirror::Class> inf_klass =
1165           art::mirror::Class::ResolveDirectInterface(self, h_klass, i);
1166       if (inf_klass == nullptr) {
1167         // TODO: With a resolved class this should not happen...
1168         self->ClearException();
1169         break;
1170       }
1171 
1172       stop_reports_ = !ReportReferenceMaybeEnqueue(JVMTI_HEAP_REFERENCE_INTERFACE,
1173                                                    nullptr,
1174                                                    klass,
1175                                                    inf_klass.Ptr());
1176       if (stop_reports_) {
1177         return;
1178       }
1179     }
1180 
1181     // Classloader.
1182     // TODO: What about the boot classpath loader? We'll skip for now, but do we have to find the
1183     //       fake BootClassLoader?
1184     if (klass->GetClassLoader() != nullptr) {
1185       stop_reports_ = !ReportReferenceMaybeEnqueue(JVMTI_HEAP_REFERENCE_CLASS_LOADER,
1186                                                    nullptr,
1187                                                    klass,
1188                                                    klass->GetClassLoader());
1189       if (stop_reports_) {
1190         return;
1191       }
1192     }
1193     DCHECK_EQ(h_klass.Get(), klass);
1194 
1195     // Declared static fields.
1196     auto report_static_field = [&](art::ObjPtr<art::mirror::Object> obj ATTRIBUTE_UNUSED,
1197                                    art::ObjPtr<art::mirror::Class> obj_klass,
1198                                    art::ArtField& field,
1199                                    size_t field_index,
1200                                    void* user_data ATTRIBUTE_UNUSED)
1201         REQUIRES_SHARED(art::Locks::mutator_lock_)
1202         REQUIRES(!*tag_table_->GetAllowDisallowLock()) {
1203       art::ObjPtr<art::mirror::Object> field_value = field.GetObject(obj_klass);
1204       if (field_value != nullptr) {
1205         jvmtiHeapReferenceInfo reference_info;
1206         memset(&reference_info, 0, sizeof(reference_info));
1207 
1208         reference_info.field.index = static_cast<jint>(field_index);
1209 
1210         return !ReportReferenceMaybeEnqueue(JVMTI_HEAP_REFERENCE_STATIC_FIELD,
1211                                             &reference_info,
1212                                             obj_klass.Ptr(),
1213                                             field_value.Ptr());
1214       }
1215       return false;
1216     };
1217     stop_reports_ = FieldVisitor<void, false>::ReportFields(klass,
1218                                                             nullptr,
1219                                                             VisitorFalse<void>,
1220                                                             report_static_field,
1221                                                             VisitorFalse<void>,
1222                                                             VisitorFalse<void>);
1223     if (stop_reports_) {
1224       return;
1225     }
1226 
1227     stop_reports_ = ReportPrimitiveField::Report(klass, tag_table_, callbacks_, user_data_);
1228   }
1229 
MaybeEnqueue(art::mirror::Object * obj)1230   void MaybeEnqueue(art::mirror::Object* obj) REQUIRES_SHARED(art::Locks::mutator_lock_) {
1231     if (visited_.find(obj) == visited_.end()) {
1232       worklist_.push_back(obj);
1233       visited_.insert(obj);
1234     }
1235   }
1236 
ReportReferenceMaybeEnqueue(jvmtiHeapReferenceKind kind,const jvmtiHeapReferenceInfo * reference_info,art::mirror::Object * referree,art::mirror::Object * referrer)1237   bool ReportReferenceMaybeEnqueue(jvmtiHeapReferenceKind kind,
1238                                    const jvmtiHeapReferenceInfo* reference_info,
1239                                    art::mirror::Object* referree,
1240                                    art::mirror::Object* referrer)
1241       REQUIRES_SHARED(art::Locks::mutator_lock_)
1242       REQUIRES(!*tag_table_->GetAllowDisallowLock()) {
1243     jint result = ReportReference(kind, reference_info, referree, referrer);
1244     if ((result & JVMTI_VISIT_ABORT) == 0) {
1245       if ((result & JVMTI_VISIT_OBJECTS) != 0) {
1246         MaybeEnqueue(referrer);
1247       }
1248       return true;
1249     } else {
1250       return false;
1251     }
1252   }
1253 
ReportReference(jvmtiHeapReferenceKind kind,const jvmtiHeapReferenceInfo * reference_info,art::mirror::Object * referrer,art::mirror::Object * referree)1254   jint ReportReference(jvmtiHeapReferenceKind kind,
1255                        const jvmtiHeapReferenceInfo* reference_info,
1256                        art::mirror::Object* referrer,
1257                        art::mirror::Object* referree)
1258       REQUIRES_SHARED(art::Locks::mutator_lock_)
1259       REQUIRES(!*tag_table_->GetAllowDisallowLock()) {
1260     if (referree == nullptr || stop_reports_) {
1261       return 0;
1262     }
1263 
1264     if (UNLIKELY(class_filter_ != nullptr) && class_filter_ != referree->GetClass()) {
1265       return JVMTI_VISIT_OBJECTS;
1266     }
1267 
1268     const jlong class_tag = tag_table_->GetTagOrZero(referree->GetClass());
1269     jlong tag = tag_table_->GetTagOrZero(referree);
1270 
1271     if (!heap_filter_.ShouldReportByHeapFilter(tag, class_tag)) {
1272       return JVMTI_VISIT_OBJECTS;
1273     }
1274 
1275     const jlong referrer_class_tag =
1276         referrer == nullptr ? 0 : tag_table_->GetTagOrZero(referrer->GetClass());
1277     const jlong size = static_cast<jlong>(referree->SizeOf());
1278     jlong saved_tag = tag;
1279     jlong referrer_tag = 0;
1280     jlong saved_referrer_tag = 0;
1281     jlong* referrer_tag_ptr;
1282     if (referrer == nullptr) {
1283       referrer_tag_ptr = nullptr;
1284     } else {
1285       if (referrer == referree) {
1286         referrer_tag_ptr = &tag;
1287       } else {
1288         referrer_tag = saved_referrer_tag = tag_table_->GetTagOrZero(referrer);
1289         referrer_tag_ptr = &referrer_tag;
1290       }
1291     }
1292 
1293     jint length = -1;
1294     if (referree->IsArrayInstance()) {
1295       length = referree->AsArray()->GetLength();
1296     }
1297 
1298     jint result = callbacks_->heap_reference_callback(kind,
1299                                                       reference_info,
1300                                                       class_tag,
1301                                                       referrer_class_tag,
1302                                                       size,
1303                                                       &tag,
1304                                                       referrer_tag_ptr,
1305                                                       length,
1306                                                       const_cast<void*>(user_data_));
1307 
1308     if (tag != saved_tag) {
1309       tag_table_->Set(referree, tag);
1310     }
1311     if (referrer_tag != saved_referrer_tag) {
1312       tag_table_->Set(referrer, referrer_tag);
1313     }
1314 
1315     return result;
1316   }
1317 
1318   jvmtiEnv* env;
1319   ObjectTagTable* tag_table_;
1320   art::ObjPtr<art::mirror::Object> initial_object_;
1321   const jvmtiHeapCallbacks* callbacks_;
1322   art::ObjPtr<art::mirror::Class> class_filter_;
1323   const HeapFilter heap_filter_;
1324   const void* user_data_;
1325 
1326   std::vector<art::mirror::Object*> worklist_;
1327   size_t start_;
1328   static constexpr size_t kMaxStart = 1000000U;
1329 
1330   std::unordered_set<art::mirror::Object*> visited_;
1331 
1332   bool stop_reports_;
1333 
1334   friend class CollectAndReportRootsVisitor;
1335 };
1336 
FollowReferences(jvmtiEnv * env,jint heap_filter,jclass klass,jobject initial_object,const jvmtiHeapCallbacks * callbacks,const void * user_data)1337 jvmtiError HeapUtil::FollowReferences(jvmtiEnv* env,
1338                                       jint heap_filter,
1339                                       jclass klass,
1340                                       jobject initial_object,
1341                                       const jvmtiHeapCallbacks* callbacks,
1342                                       const void* user_data) {
1343   if (callbacks == nullptr) {
1344     return ERR(NULL_POINTER);
1345   }
1346 
1347   art::Thread* self = art::Thread::Current();
1348 
1349   art::gc::Heap* heap = art::Runtime::Current()->GetHeap();
1350   if (heap->IsGcConcurrentAndMoving()) {
1351     // Need to take a heap dump while GC isn't running. See the
1352     // comment in Heap::VisitObjects().
1353     heap->IncrementDisableMovingGC(self);
1354   }
1355   {
1356     art::ScopedObjectAccess soa(self);      // Now we know we have the shared lock.
1357     art::ScopedThreadSuspension sts(self, art::kWaitingForVisitObjects);
1358     art::ScopedSuspendAll ssa("FollowReferences");
1359 
1360     art::ObjPtr<art::mirror::Class> class_filter = klass == nullptr
1361         ? nullptr
1362         : art::ObjPtr<art::mirror::Class>::DownCast(self->DecodeJObject(klass));
1363     FollowReferencesHelper frh(this,
1364                                env,
1365                                self->DecodeJObject(initial_object),
1366                                callbacks,
1367                                class_filter,
1368                                heap_filter,
1369                                user_data);
1370     frh.Init();
1371     frh.Work();
1372   }
1373   if (heap->IsGcConcurrentAndMoving()) {
1374     heap->DecrementDisableMovingGC(self);
1375   }
1376 
1377   return ERR(NONE);
1378 }
1379 
GetLoadedClasses(jvmtiEnv * env,jint * class_count_ptr,jclass ** classes_ptr)1380 jvmtiError HeapUtil::GetLoadedClasses(jvmtiEnv* env,
1381                                       jint* class_count_ptr,
1382                                       jclass** classes_ptr) {
1383   if (class_count_ptr == nullptr || classes_ptr == nullptr) {
1384     return ERR(NULL_POINTER);
1385   }
1386 
1387   class ReportClassVisitor : public art::ClassVisitor {
1388    public:
1389     explicit ReportClassVisitor(art::Thread* self) : self_(self) {}
1390 
1391     bool operator()(art::ObjPtr<art::mirror::Class> klass)
1392         OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) {
1393       classes_.push_back(self_->GetJniEnv()->AddLocalReference<jclass>(klass));
1394       return true;
1395     }
1396 
1397     art::Thread* self_;
1398     std::vector<jclass> classes_;
1399   };
1400 
1401   art::Thread* self = art::Thread::Current();
1402   ReportClassVisitor rcv(self);
1403   {
1404     art::ScopedObjectAccess soa(self);
1405     art::Runtime::Current()->GetClassLinker()->VisitClasses(&rcv);
1406   }
1407 
1408   size_t size = rcv.classes_.size();
1409   jclass* classes = nullptr;
1410   jvmtiError alloc_ret = env->Allocate(static_cast<jlong>(size * sizeof(jclass)),
1411                                        reinterpret_cast<unsigned char**>(&classes));
1412   if (alloc_ret != ERR(NONE)) {
1413     return alloc_ret;
1414   }
1415 
1416   for (size_t i = 0; i < size; ++i) {
1417     classes[i] = rcv.classes_[i];
1418   }
1419   *classes_ptr = classes;
1420   *class_count_ptr = static_cast<jint>(size);
1421 
1422   return ERR(NONE);
1423 }
1424 
ForceGarbageCollection(jvmtiEnv * env ATTRIBUTE_UNUSED)1425 jvmtiError HeapUtil::ForceGarbageCollection(jvmtiEnv* env ATTRIBUTE_UNUSED) {
1426   art::Runtime::Current()->GetHeap()->CollectGarbage(false);
1427 
1428   return ERR(NONE);
1429 }
1430 
1431 static constexpr jint kHeapIdDefault = 0;
1432 static constexpr jint kHeapIdImage = 1;
1433 static constexpr jint kHeapIdZygote = 2;
1434 static constexpr jint kHeapIdApp = 3;
1435 
GetHeapId(art::ObjPtr<art::mirror::Object> obj)1436 static jint GetHeapId(art::ObjPtr<art::mirror::Object> obj)
1437     REQUIRES_SHARED(art::Locks::mutator_lock_) {
1438   if (obj == nullptr) {
1439     return -1;
1440   }
1441 
1442   art::gc::Heap* const heap = art::Runtime::Current()->GetHeap();
1443   const art::gc::space::ContinuousSpace* const space =
1444       heap->FindContinuousSpaceFromObject(obj, true);
1445   jint heap_type = kHeapIdApp;
1446   if (space != nullptr) {
1447     if (space->IsZygoteSpace()) {
1448       heap_type = kHeapIdZygote;
1449     } else if (space->IsImageSpace() && heap->ObjectIsInBootImageSpace(obj)) {
1450       // Only count objects in the boot image as HPROF_HEAP_IMAGE, this leaves app image objects
1451       // as HPROF_HEAP_APP. b/35762934
1452       heap_type = kHeapIdImage;
1453     }
1454   } else {
1455     const auto* los = heap->GetLargeObjectsSpace();
1456     if (los->Contains(obj.Ptr()) && los->IsZygoteLargeObject(art::Thread::Current(), obj.Ptr())) {
1457       heap_type = kHeapIdZygote;
1458     }
1459   }
1460   return heap_type;
1461 };
1462 
GetObjectHeapId(jvmtiEnv * env,jlong tag,jint * heap_id,...)1463 jvmtiError HeapExtensions::GetObjectHeapId(jvmtiEnv* env, jlong tag, jint* heap_id, ...) {
1464   if (heap_id == nullptr) {
1465     return ERR(NULL_POINTER);
1466   }
1467 
1468   art::Thread* self = art::Thread::Current();
1469 
1470   auto work = [&]() REQUIRES_SHARED(art::Locks::mutator_lock_) {
1471     ObjectTagTable* tag_table = ArtJvmTiEnv::AsArtJvmTiEnv(env)->object_tag_table.get();
1472     art::ObjPtr<art::mirror::Object> obj = tag_table->Find(tag);
1473     jint heap_type = GetHeapId(obj);
1474     if (heap_type == -1) {
1475       return ERR(NOT_FOUND);
1476     }
1477     *heap_id = heap_type;
1478     return ERR(NONE);
1479   };
1480 
1481   if (!art::Locks::mutator_lock_->IsSharedHeld(self)) {
1482     if (!self->IsThreadSuspensionAllowable()) {
1483       return ERR(INTERNAL);
1484     }
1485     art::ScopedObjectAccess soa(self);
1486     return work();
1487   } else {
1488     // We cannot use SOA in this case. We might be holding the lock, but may not be in the
1489     // runnable state (e.g., during GC).
1490     art::Locks::mutator_lock_->AssertSharedHeld(self);
1491     // TODO: Investigate why ASSERT_SHARED_CAPABILITY doesn't work.
1492     auto annotalysis_workaround = [&]() NO_THREAD_SAFETY_ANALYSIS {
1493       return work();
1494     };
1495     return annotalysis_workaround();
1496   }
1497 }
1498 
CopyStringAndReturn(jvmtiEnv * env,const char * in,char ** out)1499 static jvmtiError CopyStringAndReturn(jvmtiEnv* env, const char* in, char** out) {
1500   jvmtiError error;
1501   JvmtiUniquePtr<char[]> param_name = CopyString(env, in, &error);
1502   if (param_name == nullptr) {
1503     return error;
1504   }
1505   *out = param_name.release();
1506   return ERR(NONE);
1507 }
1508 
1509 static constexpr const char* kHeapIdDefaultName = "default";
1510 static constexpr const char* kHeapIdImageName = "image";
1511 static constexpr const char* kHeapIdZygoteName = "zygote";
1512 static constexpr const char* kHeapIdAppName = "app";
1513 
GetHeapName(jvmtiEnv * env,jint heap_id,char ** heap_name,...)1514 jvmtiError HeapExtensions::GetHeapName(jvmtiEnv* env, jint heap_id, char** heap_name, ...) {
1515   switch (heap_id) {
1516     case kHeapIdDefault:
1517       return CopyStringAndReturn(env, kHeapIdDefaultName, heap_name);
1518     case kHeapIdImage:
1519       return CopyStringAndReturn(env, kHeapIdImageName, heap_name);
1520     case kHeapIdZygote:
1521       return CopyStringAndReturn(env, kHeapIdZygoteName, heap_name);
1522     case kHeapIdApp:
1523       return CopyStringAndReturn(env, kHeapIdAppName, heap_name);
1524 
1525     default:
1526       return ERR(ILLEGAL_ARGUMENT);
1527   }
1528 }
1529 
IterateThroughHeapExt(jvmtiEnv * env,jint heap_filter,jclass klass,const jvmtiHeapCallbacks * callbacks,const void * user_data)1530 jvmtiError HeapExtensions::IterateThroughHeapExt(jvmtiEnv* env,
1531                                                  jint heap_filter,
1532                                                  jclass klass,
1533                                                  const jvmtiHeapCallbacks* callbacks,
1534                                                  const void* user_data) {
1535   if (ArtJvmTiEnv::AsArtJvmTiEnv(env)->capabilities.can_tag_objects != 1) { \
1536     return ERR(MUST_POSSESS_CAPABILITY); \
1537   }
1538 
1539   // ART extension API: Also pass the heap id.
1540   auto ArtIterateHeap = [](art::mirror::Object* obj,
1541                            const jvmtiHeapCallbacks* cb_callbacks,
1542                            jlong class_tag,
1543                            jlong size,
1544                            jlong* tag,
1545                            jint length,
1546                            void* cb_user_data)
1547       REQUIRES_SHARED(art::Locks::mutator_lock_) {
1548     jint heap_id = GetHeapId(obj);
1549     using ArtExtensionAPI = jint (*)(jlong, jlong, jlong*, jint length, void*, jint);
1550     return reinterpret_cast<ArtExtensionAPI>(cb_callbacks->heap_iteration_callback)(
1551         class_tag, size, tag, length, cb_user_data, heap_id);
1552   };
1553   return DoIterateThroughHeap(ArtIterateHeap,
1554                               env,
1555                               ArtJvmTiEnv::AsArtJvmTiEnv(env)->object_tag_table.get(),
1556                               heap_filter,
1557                               klass,
1558                               callbacks,
1559                               user_data);
1560 }
1561 
1562 }  // namespace openjdkjvmti
1563