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