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/heap-visit-objects-inl.h" 26 #include "gc_root-inl.h" 27 #include "java_frame_root_info.h" 28 #include "jni_env_ext.h" 29 #include "jni_internal.h" 30 #include "jvmti_weak_table-inl.h" 31 #include "mirror/class.h" 32 #include "mirror/object-inl.h" 33 #include "mirror/object_array-inl.h" 34 #include "object_tagging.h" 35 #include "obj_ptr-inl.h" 36 #include "primitive.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 template <typename T> 657 static jvmtiError DoIterateThroughHeap(T fn, 658 jvmtiEnv* env, 659 ObjectTagTable* tag_table, 660 jint heap_filter_int, 661 jclass klass, 662 const jvmtiHeapCallbacks* callbacks, 663 const void* user_data) { 664 if (callbacks == nullptr) { 665 return ERR(NULL_POINTER); 666 } 667 668 art::Thread* self = art::Thread::Current(); 669 art::ScopedObjectAccess soa(self); // Now we know we have the shared lock. 670 671 bool stop_reports = false; 672 const HeapFilter heap_filter(heap_filter_int); 673 art::ObjPtr<art::mirror::Class> filter_klass = soa.Decode<art::mirror::Class>(klass); 674 auto visitor = [&](art::mirror::Object* obj) REQUIRES_SHARED(art::Locks::mutator_lock_) { 675 // Early return, as we can't really stop visiting. 676 if (stop_reports) { 677 return; 678 } 679 680 art::ScopedAssertNoThreadSuspension no_suspension("IterateThroughHeapCallback"); 681 682 jlong tag = 0; 683 tag_table->GetTag(obj, &tag); 684 685 jlong class_tag = 0; 686 art::ObjPtr<art::mirror::Class> klass = obj->GetClass(); 687 tag_table->GetTag(klass.Ptr(), &class_tag); 688 // For simplicity, even if we find a tag = 0, assume 0 = not tagged. 689 690 if (!heap_filter.ShouldReportByHeapFilter(tag, class_tag)) { 691 return; 692 } 693 694 if (filter_klass != nullptr) { 695 if (filter_klass != klass) { 696 return; 697 } 698 } 699 700 jlong size = obj->SizeOf(); 701 702 jint length = -1; 703 if (obj->IsArrayInstance()) { 704 length = obj->AsArray()->GetLength(); 705 } 706 707 jlong saved_tag = tag; 708 jint ret = fn(obj, callbacks, class_tag, size, &tag, length, const_cast<void*>(user_data)); 709 710 if (tag != saved_tag) { 711 tag_table->Set(obj, tag); 712 } 713 714 stop_reports = (ret & JVMTI_VISIT_ABORT) != 0; 715 716 if (!stop_reports) { 717 jint string_ret = ReportString(obj, env, tag_table, callbacks, user_data); 718 stop_reports = (string_ret & JVMTI_VISIT_ABORT) != 0; 719 } 720 721 if (!stop_reports) { 722 jint array_ret = ReportPrimitiveArray(obj, env, tag_table, callbacks, user_data); 723 stop_reports = (array_ret & JVMTI_VISIT_ABORT) != 0; 724 } 725 726 if (!stop_reports) { 727 stop_reports = ReportPrimitiveField::Report(obj, tag_table, callbacks, user_data); 728 } 729 }; 730 art::Runtime::Current()->GetHeap()->VisitObjects(visitor); 731 732 return ERR(NONE); 733 } 734 735 jvmtiError HeapUtil::IterateThroughHeap(jvmtiEnv* env, 736 jint heap_filter, 737 jclass klass, 738 const jvmtiHeapCallbacks* callbacks, 739 const void* user_data) { 740 auto JvmtiIterateHeap = [](art::mirror::Object* obj ATTRIBUTE_UNUSED, 741 const jvmtiHeapCallbacks* cb_callbacks, 742 jlong class_tag, 743 jlong size, 744 jlong* tag, 745 jint length, 746 void* cb_user_data) 747 REQUIRES_SHARED(art::Locks::mutator_lock_) { 748 return cb_callbacks->heap_iteration_callback(class_tag, 749 size, 750 tag, 751 length, 752 cb_user_data); 753 }; 754 return DoIterateThroughHeap(JvmtiIterateHeap, 755 env, 756 ArtJvmTiEnv::AsArtJvmTiEnv(env)->object_tag_table.get(), 757 heap_filter, 758 klass, 759 callbacks, 760 user_data); 761 } 762 763 class FollowReferencesHelper FINAL { 764 public: 765 FollowReferencesHelper(HeapUtil* h, 766 jvmtiEnv* jvmti_env, 767 art::ObjPtr<art::mirror::Object> initial_object, 768 const jvmtiHeapCallbacks* callbacks, 769 art::ObjPtr<art::mirror::Class> class_filter, 770 jint heap_filter, 771 const void* user_data) 772 : env(jvmti_env), 773 tag_table_(h->GetTags()), 774 initial_object_(initial_object), 775 callbacks_(callbacks), 776 class_filter_(class_filter), 777 heap_filter_(heap_filter), 778 user_data_(user_data), 779 start_(0), 780 stop_reports_(false) { 781 } 782 783 void Init() 784 REQUIRES_SHARED(art::Locks::mutator_lock_) 785 REQUIRES(!*tag_table_->GetAllowDisallowLock()) { 786 if (initial_object_.IsNull()) { 787 CollectAndReportRootsVisitor carrv(this, tag_table_, &worklist_, &visited_); 788 789 // We need precise info (e.g., vregs). 790 constexpr art::VisitRootFlags kRootFlags = static_cast<art::VisitRootFlags>( 791 art::VisitRootFlags::kVisitRootFlagAllRoots | art::VisitRootFlags::kVisitRootFlagPrecise); 792 art::Runtime::Current()->VisitRoots(&carrv, kRootFlags); 793 794 art::Runtime::Current()->VisitImageRoots(&carrv); 795 stop_reports_ = carrv.IsStopReports(); 796 797 if (stop_reports_) { 798 worklist_.clear(); 799 } 800 } else { 801 visited_.insert(initial_object_.Ptr()); 802 worklist_.push_back(initial_object_.Ptr()); 803 } 804 } 805 806 void Work() 807 REQUIRES_SHARED(art::Locks::mutator_lock_) 808 REQUIRES(!*tag_table_->GetAllowDisallowLock()) { 809 // Currently implemented as a BFS. To lower overhead, we don't erase elements immediately 810 // from the head of the work list, instead postponing until there's a gap that's "large." 811 // 812 // Alternatively, we can implement a DFS and use the work list as a stack. 813 while (start_ < worklist_.size()) { 814 art::mirror::Object* cur_obj = worklist_[start_]; 815 start_++; 816 817 if (start_ >= kMaxStart) { 818 worklist_.erase(worklist_.begin(), worklist_.begin() + start_); 819 start_ = 0; 820 } 821 822 VisitObject(cur_obj); 823 824 if (stop_reports_) { 825 break; 826 } 827 } 828 } 829 830 private: 831 class CollectAndReportRootsVisitor FINAL : public art::RootVisitor { 832 public: 833 CollectAndReportRootsVisitor(FollowReferencesHelper* helper, 834 ObjectTagTable* tag_table, 835 std::vector<art::mirror::Object*>* worklist, 836 std::unordered_set<art::mirror::Object*>* visited) 837 : helper_(helper), 838 tag_table_(tag_table), 839 worklist_(worklist), 840 visited_(visited), 841 stop_reports_(false) {} 842 843 void VisitRoots(art::mirror::Object*** roots, size_t count, const art::RootInfo& info) 844 OVERRIDE 845 REQUIRES_SHARED(art::Locks::mutator_lock_) 846 REQUIRES(!*helper_->tag_table_->GetAllowDisallowLock()) { 847 for (size_t i = 0; i != count; ++i) { 848 AddRoot(*roots[i], info); 849 } 850 } 851 852 void VisitRoots(art::mirror::CompressedReference<art::mirror::Object>** roots, 853 size_t count, 854 const art::RootInfo& info) 855 OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) 856 REQUIRES(!*helper_->tag_table_->GetAllowDisallowLock()) { 857 for (size_t i = 0; i != count; ++i) { 858 AddRoot(roots[i]->AsMirrorPtr(), info); 859 } 860 } 861 862 bool IsStopReports() { 863 return stop_reports_; 864 } 865 866 private: 867 void AddRoot(art::mirror::Object* root_obj, const art::RootInfo& info) 868 REQUIRES_SHARED(art::Locks::mutator_lock_) 869 REQUIRES(!*tag_table_->GetAllowDisallowLock()) { 870 if (stop_reports_) { 871 return; 872 } 873 bool add_to_worklist = ReportRoot(root_obj, info); 874 // We use visited_ to mark roots already so we do not need another set. 875 if (visited_->find(root_obj) == visited_->end()) { 876 if (add_to_worklist) { 877 visited_->insert(root_obj); 878 worklist_->push_back(root_obj); 879 } 880 } 881 } 882 883 // Remove NO_THREAD_SAFETY_ANALYSIS once ASSERT_CAPABILITY works correctly. 884 art::Thread* FindThread(const art::RootInfo& info) NO_THREAD_SAFETY_ANALYSIS { 885 art::Locks::thread_list_lock_->AssertExclusiveHeld(art::Thread::Current()); 886 return art::Runtime::Current()->GetThreadList()->FindThreadByThreadId(info.GetThreadId()); 887 } 888 889 jvmtiHeapReferenceKind GetReferenceKind(const art::RootInfo& info, 890 jvmtiHeapReferenceInfo* ref_info) 891 REQUIRES_SHARED(art::Locks::mutator_lock_) { 892 // TODO: Fill in ref_info. 893 memset(ref_info, 0, sizeof(jvmtiHeapReferenceInfo)); 894 895 switch (info.GetType()) { 896 case art::RootType::kRootJNIGlobal: 897 return JVMTI_HEAP_REFERENCE_JNI_GLOBAL; 898 899 case art::RootType::kRootJNILocal: 900 { 901 uint32_t thread_id = info.GetThreadId(); 902 ref_info->jni_local.thread_id = thread_id; 903 904 art::Thread* thread = FindThread(info); 905 if (thread != nullptr) { 906 art::mirror::Object* thread_obj; 907 if (thread->IsStillStarting()) { 908 thread_obj = nullptr; 909 } else { 910 thread_obj = thread->GetPeerFromOtherThread(); 911 } 912 if (thread_obj != nullptr) { 913 ref_info->jni_local.thread_tag = tag_table_->GetTagOrZero(thread_obj); 914 } 915 } 916 917 // TODO: We don't have this info. 918 if (thread != nullptr) { 919 ref_info->jni_local.depth = 0; 920 art::ArtMethod* method = thread->GetCurrentMethod(nullptr, false /* abort_on_error */); 921 if (method != nullptr) { 922 ref_info->jni_local.method = art::jni::EncodeArtMethod(method); 923 } 924 } 925 926 return JVMTI_HEAP_REFERENCE_JNI_LOCAL; 927 } 928 929 case art::RootType::kRootJavaFrame: 930 { 931 uint32_t thread_id = info.GetThreadId(); 932 ref_info->stack_local.thread_id = thread_id; 933 934 art::Thread* thread = FindThread(info); 935 if (thread != nullptr) { 936 art::mirror::Object* thread_obj; 937 if (thread->IsStillStarting()) { 938 thread_obj = nullptr; 939 } else { 940 thread_obj = thread->GetPeerFromOtherThread(); 941 } 942 if (thread_obj != nullptr) { 943 ref_info->stack_local.thread_tag = tag_table_->GetTagOrZero(thread_obj); 944 } 945 } 946 947 auto& java_info = static_cast<const art::JavaFrameRootInfo&>(info); 948 ref_info->stack_local.slot = static_cast<jint>(java_info.GetVReg()); 949 const art::StackVisitor* visitor = java_info.GetVisitor(); 950 ref_info->stack_local.location = 951 static_cast<jlocation>(visitor->GetDexPc(false /* abort_on_failure */)); 952 ref_info->stack_local.depth = static_cast<jint>(visitor->GetFrameDepth()); 953 art::ArtMethod* method = visitor->GetMethod(); 954 if (method != nullptr) { 955 ref_info->stack_local.method = art::jni::EncodeArtMethod(method); 956 } 957 958 return JVMTI_HEAP_REFERENCE_STACK_LOCAL; 959 } 960 961 case art::RootType::kRootNativeStack: 962 case art::RootType::kRootThreadBlock: 963 case art::RootType::kRootThreadObject: 964 return JVMTI_HEAP_REFERENCE_THREAD; 965 966 case art::RootType::kRootStickyClass: 967 case art::RootType::kRootInternedString: 968 // Note: this isn't a root in the RI. 969 return JVMTI_HEAP_REFERENCE_SYSTEM_CLASS; 970 971 case art::RootType::kRootMonitorUsed: 972 case art::RootType::kRootJNIMonitor: 973 return JVMTI_HEAP_REFERENCE_MONITOR; 974 975 case art::RootType::kRootFinalizing: 976 case art::RootType::kRootDebugger: 977 case art::RootType::kRootReferenceCleanup: 978 case art::RootType::kRootVMInternal: 979 case art::RootType::kRootUnknown: 980 return JVMTI_HEAP_REFERENCE_OTHER; 981 } 982 LOG(FATAL) << "Unreachable"; 983 UNREACHABLE(); 984 } 985 986 bool ReportRoot(art::mirror::Object* root_obj, const art::RootInfo& info) 987 REQUIRES_SHARED(art::Locks::mutator_lock_) 988 REQUIRES(!*tag_table_->GetAllowDisallowLock()) { 989 jvmtiHeapReferenceInfo ref_info; 990 jvmtiHeapReferenceKind kind = GetReferenceKind(info, &ref_info); 991 jint result = helper_->ReportReference(kind, &ref_info, nullptr, root_obj); 992 if ((result & JVMTI_VISIT_ABORT) != 0) { 993 stop_reports_ = true; 994 } 995 return (result & JVMTI_VISIT_OBJECTS) != 0; 996 } 997 998 private: 999 FollowReferencesHelper* helper_; 1000 ObjectTagTable* tag_table_; 1001 std::vector<art::mirror::Object*>* worklist_; 1002 std::unordered_set<art::mirror::Object*>* visited_; 1003 bool stop_reports_; 1004 }; 1005 1006 void VisitObject(art::mirror::Object* obj) 1007 REQUIRES_SHARED(art::Locks::mutator_lock_) 1008 REQUIRES(!*tag_table_->GetAllowDisallowLock()) { 1009 if (obj->IsClass()) { 1010 VisitClass(obj->AsClass()); 1011 return; 1012 } 1013 if (obj->IsArrayInstance()) { 1014 VisitArray(obj); 1015 return; 1016 } 1017 1018 // All instance fields. 1019 auto report_instance_field = [&](art::ObjPtr<art::mirror::Object> src, 1020 art::ObjPtr<art::mirror::Class> obj_klass ATTRIBUTE_UNUSED, 1021 art::ArtField& field, 1022 size_t field_index, 1023 void* user_data ATTRIBUTE_UNUSED) 1024 REQUIRES_SHARED(art::Locks::mutator_lock_) 1025 REQUIRES(!*tag_table_->GetAllowDisallowLock()) { 1026 art::ObjPtr<art::mirror::Object> field_value = field.GetObject(src); 1027 if (field_value != nullptr) { 1028 jvmtiHeapReferenceInfo reference_info; 1029 memset(&reference_info, 0, sizeof(reference_info)); 1030 1031 reference_info.field.index = field_index; 1032 1033 jvmtiHeapReferenceKind kind = 1034 field.GetOffset().Int32Value() == art::mirror::Object::ClassOffset().Int32Value() 1035 ? JVMTI_HEAP_REFERENCE_CLASS 1036 : JVMTI_HEAP_REFERENCE_FIELD; 1037 const jvmtiHeapReferenceInfo* reference_info_ptr = 1038 kind == JVMTI_HEAP_REFERENCE_CLASS ? nullptr : &reference_info; 1039 1040 return !ReportReferenceMaybeEnqueue(kind, reference_info_ptr, src.Ptr(), field_value.Ptr()); 1041 } 1042 return false; 1043 }; 1044 stop_reports_ = FieldVisitor<void, true>::ReportFields(obj, 1045 nullptr, 1046 VisitorFalse<void>, 1047 VisitorFalse<void>, 1048 VisitorFalse<void>, 1049 report_instance_field); 1050 if (stop_reports_) { 1051 return; 1052 } 1053 1054 jint string_ret = ReportString(obj, env, tag_table_, callbacks_, user_data_); 1055 stop_reports_ = (string_ret & JVMTI_VISIT_ABORT) != 0; 1056 if (stop_reports_) { 1057 return; 1058 } 1059 1060 stop_reports_ = ReportPrimitiveField::Report(obj, tag_table_, callbacks_, user_data_); 1061 } 1062 1063 void VisitArray(art::mirror::Object* array) 1064 REQUIRES_SHARED(art::Locks::mutator_lock_) 1065 REQUIRES(!*tag_table_->GetAllowDisallowLock()) { 1066 stop_reports_ = !ReportReferenceMaybeEnqueue(JVMTI_HEAP_REFERENCE_CLASS, 1067 nullptr, 1068 array, 1069 array->GetClass()); 1070 if (stop_reports_) { 1071 return; 1072 } 1073 1074 if (array->IsObjectArray()) { 1075 art::mirror::ObjectArray<art::mirror::Object>* obj_array = 1076 array->AsObjectArray<art::mirror::Object>(); 1077 int32_t length = obj_array->GetLength(); 1078 for (int32_t i = 0; i != length; ++i) { 1079 art::mirror::Object* elem = obj_array->GetWithoutChecks(i); 1080 if (elem != nullptr) { 1081 jvmtiHeapReferenceInfo reference_info; 1082 reference_info.array.index = i; 1083 stop_reports_ = !ReportReferenceMaybeEnqueue(JVMTI_HEAP_REFERENCE_ARRAY_ELEMENT, 1084 &reference_info, 1085 array, 1086 elem); 1087 if (stop_reports_) { 1088 break; 1089 } 1090 } 1091 } 1092 } else { 1093 if (!stop_reports_) { 1094 jint array_ret = ReportPrimitiveArray(array, env, tag_table_, callbacks_, user_data_); 1095 stop_reports_ = (array_ret & JVMTI_VISIT_ABORT) != 0; 1096 } 1097 } 1098 } 1099 1100 void VisitClass(art::mirror::Class* klass) 1101 REQUIRES_SHARED(art::Locks::mutator_lock_) 1102 REQUIRES(!*tag_table_->GetAllowDisallowLock()) { 1103 // TODO: Are erroneous classes reported? Are non-prepared ones? For now, just use resolved ones. 1104 if (!klass->IsResolved()) { 1105 return; 1106 } 1107 1108 // Superclass. 1109 stop_reports_ = !ReportReferenceMaybeEnqueue(JVMTI_HEAP_REFERENCE_SUPERCLASS, 1110 nullptr, 1111 klass, 1112 klass->GetSuperClass()); 1113 if (stop_reports_) { 1114 return; 1115 } 1116 1117 // Directly implemented or extended interfaces. 1118 art::Thread* self = art::Thread::Current(); 1119 art::StackHandleScope<1> hs(self); 1120 art::Handle<art::mirror::Class> h_klass(hs.NewHandle<art::mirror::Class>(klass)); 1121 for (size_t i = 0; i < h_klass->NumDirectInterfaces(); ++i) { 1122 art::ObjPtr<art::mirror::Class> inf_klass = 1123 art::mirror::Class::ResolveDirectInterface(self, h_klass, i); 1124 if (inf_klass == nullptr) { 1125 // TODO: With a resolved class this should not happen... 1126 self->ClearException(); 1127 break; 1128 } 1129 1130 stop_reports_ = !ReportReferenceMaybeEnqueue(JVMTI_HEAP_REFERENCE_INTERFACE, 1131 nullptr, 1132 klass, 1133 inf_klass.Ptr()); 1134 if (stop_reports_) { 1135 return; 1136 } 1137 } 1138 1139 // Classloader. 1140 // TODO: What about the boot classpath loader? We'll skip for now, but do we have to find the 1141 // fake BootClassLoader? 1142 if (klass->GetClassLoader() != nullptr) { 1143 stop_reports_ = !ReportReferenceMaybeEnqueue(JVMTI_HEAP_REFERENCE_CLASS_LOADER, 1144 nullptr, 1145 klass, 1146 klass->GetClassLoader()); 1147 if (stop_reports_) { 1148 return; 1149 } 1150 } 1151 DCHECK_EQ(h_klass.Get(), klass); 1152 1153 // Declared static fields. 1154 auto report_static_field = [&](art::ObjPtr<art::mirror::Object> obj ATTRIBUTE_UNUSED, 1155 art::ObjPtr<art::mirror::Class> obj_klass, 1156 art::ArtField& field, 1157 size_t field_index, 1158 void* user_data ATTRIBUTE_UNUSED) 1159 REQUIRES_SHARED(art::Locks::mutator_lock_) 1160 REQUIRES(!*tag_table_->GetAllowDisallowLock()) { 1161 art::ObjPtr<art::mirror::Object> field_value = field.GetObject(obj_klass); 1162 if (field_value != nullptr) { 1163 jvmtiHeapReferenceInfo reference_info; 1164 memset(&reference_info, 0, sizeof(reference_info)); 1165 1166 reference_info.field.index = static_cast<jint>(field_index); 1167 1168 return !ReportReferenceMaybeEnqueue(JVMTI_HEAP_REFERENCE_STATIC_FIELD, 1169 &reference_info, 1170 obj_klass.Ptr(), 1171 field_value.Ptr()); 1172 } 1173 return false; 1174 }; 1175 stop_reports_ = FieldVisitor<void, false>::ReportFields(klass, 1176 nullptr, 1177 VisitorFalse<void>, 1178 report_static_field, 1179 VisitorFalse<void>, 1180 VisitorFalse<void>); 1181 if (stop_reports_) { 1182 return; 1183 } 1184 1185 stop_reports_ = ReportPrimitiveField::Report(klass, tag_table_, callbacks_, user_data_); 1186 } 1187 1188 void MaybeEnqueue(art::mirror::Object* obj) REQUIRES_SHARED(art::Locks::mutator_lock_) { 1189 if (visited_.find(obj) == visited_.end()) { 1190 worklist_.push_back(obj); 1191 visited_.insert(obj); 1192 } 1193 } 1194 1195 bool ReportReferenceMaybeEnqueue(jvmtiHeapReferenceKind kind, 1196 const jvmtiHeapReferenceInfo* reference_info, 1197 art::mirror::Object* referree, 1198 art::mirror::Object* referrer) 1199 REQUIRES_SHARED(art::Locks::mutator_lock_) 1200 REQUIRES(!*tag_table_->GetAllowDisallowLock()) { 1201 jint result = ReportReference(kind, reference_info, referree, referrer); 1202 if ((result & JVMTI_VISIT_ABORT) == 0) { 1203 if ((result & JVMTI_VISIT_OBJECTS) != 0) { 1204 MaybeEnqueue(referrer); 1205 } 1206 return true; 1207 } else { 1208 return false; 1209 } 1210 } 1211 1212 jint ReportReference(jvmtiHeapReferenceKind kind, 1213 const jvmtiHeapReferenceInfo* reference_info, 1214 art::mirror::Object* referrer, 1215 art::mirror::Object* referree) 1216 REQUIRES_SHARED(art::Locks::mutator_lock_) 1217 REQUIRES(!*tag_table_->GetAllowDisallowLock()) { 1218 if (referree == nullptr || stop_reports_) { 1219 return 0; 1220 } 1221 1222 if (UNLIKELY(class_filter_ != nullptr) && class_filter_ != referree->GetClass()) { 1223 return JVMTI_VISIT_OBJECTS; 1224 } 1225 1226 const jlong class_tag = tag_table_->GetTagOrZero(referree->GetClass()); 1227 jlong tag = tag_table_->GetTagOrZero(referree); 1228 1229 if (!heap_filter_.ShouldReportByHeapFilter(tag, class_tag)) { 1230 return JVMTI_VISIT_OBJECTS; 1231 } 1232 1233 const jlong referrer_class_tag = 1234 referrer == nullptr ? 0 : tag_table_->GetTagOrZero(referrer->GetClass()); 1235 const jlong size = static_cast<jlong>(referree->SizeOf()); 1236 jlong saved_tag = tag; 1237 jlong referrer_tag = 0; 1238 jlong saved_referrer_tag = 0; 1239 jlong* referrer_tag_ptr; 1240 if (referrer == nullptr) { 1241 referrer_tag_ptr = nullptr; 1242 } else { 1243 if (referrer == referree) { 1244 referrer_tag_ptr = &tag; 1245 } else { 1246 referrer_tag = saved_referrer_tag = tag_table_->GetTagOrZero(referrer); 1247 referrer_tag_ptr = &referrer_tag; 1248 } 1249 } 1250 1251 jint length = -1; 1252 if (referree->IsArrayInstance()) { 1253 length = referree->AsArray()->GetLength(); 1254 } 1255 1256 jint result = callbacks_->heap_reference_callback(kind, 1257 reference_info, 1258 class_tag, 1259 referrer_class_tag, 1260 size, 1261 &tag, 1262 referrer_tag_ptr, 1263 length, 1264 const_cast<void*>(user_data_)); 1265 1266 if (tag != saved_tag) { 1267 tag_table_->Set(referree, tag); 1268 } 1269 if (referrer_tag != saved_referrer_tag) { 1270 tag_table_->Set(referrer, referrer_tag); 1271 } 1272 1273 return result; 1274 } 1275 1276 jvmtiEnv* env; 1277 ObjectTagTable* tag_table_; 1278 art::ObjPtr<art::mirror::Object> initial_object_; 1279 const jvmtiHeapCallbacks* callbacks_; 1280 art::ObjPtr<art::mirror::Class> class_filter_; 1281 const HeapFilter heap_filter_; 1282 const void* user_data_; 1283 1284 std::vector<art::mirror::Object*> worklist_; 1285 size_t start_; 1286 static constexpr size_t kMaxStart = 1000000U; 1287 1288 std::unordered_set<art::mirror::Object*> visited_; 1289 1290 bool stop_reports_; 1291 1292 friend class CollectAndReportRootsVisitor; 1293 }; 1294 1295 jvmtiError HeapUtil::FollowReferences(jvmtiEnv* env, 1296 jint heap_filter, 1297 jclass klass, 1298 jobject initial_object, 1299 const jvmtiHeapCallbacks* callbacks, 1300 const void* user_data) { 1301 if (callbacks == nullptr) { 1302 return ERR(NULL_POINTER); 1303 } 1304 1305 art::Thread* self = art::Thread::Current(); 1306 1307 art::gc::Heap* heap = art::Runtime::Current()->GetHeap(); 1308 if (heap->IsGcConcurrentAndMoving()) { 1309 // Need to take a heap dump while GC isn't running. See the 1310 // comment in Heap::VisitObjects(). 1311 heap->IncrementDisableMovingGC(self); 1312 } 1313 { 1314 art::ScopedObjectAccess soa(self); // Now we know we have the shared lock. 1315 art::ScopedThreadSuspension sts(self, art::kWaitingForVisitObjects); 1316 art::ScopedSuspendAll ssa("FollowReferences"); 1317 1318 art::ObjPtr<art::mirror::Class> class_filter = klass == nullptr 1319 ? nullptr 1320 : art::ObjPtr<art::mirror::Class>::DownCast(self->DecodeJObject(klass)); 1321 FollowReferencesHelper frh(this, 1322 env, 1323 self->DecodeJObject(initial_object), 1324 callbacks, 1325 class_filter, 1326 heap_filter, 1327 user_data); 1328 frh.Init(); 1329 frh.Work(); 1330 } 1331 if (heap->IsGcConcurrentAndMoving()) { 1332 heap->DecrementDisableMovingGC(self); 1333 } 1334 1335 return ERR(NONE); 1336 } 1337 1338 jvmtiError HeapUtil::GetLoadedClasses(jvmtiEnv* env, 1339 jint* class_count_ptr, 1340 jclass** classes_ptr) { 1341 if (class_count_ptr == nullptr || classes_ptr == nullptr) { 1342 return ERR(NULL_POINTER); 1343 } 1344 1345 class ReportClassVisitor : public art::ClassVisitor { 1346 public: 1347 explicit ReportClassVisitor(art::Thread* self) : self_(self) {} 1348 1349 bool operator()(art::ObjPtr<art::mirror::Class> klass) 1350 OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) { 1351 if (klass->IsLoaded() || klass->IsErroneous()) { 1352 classes_.push_back(self_->GetJniEnv()->AddLocalReference<jclass>(klass)); 1353 } 1354 return true; 1355 } 1356 1357 art::Thread* self_; 1358 std::vector<jclass> classes_; 1359 }; 1360 1361 art::Thread* self = art::Thread::Current(); 1362 ReportClassVisitor rcv(self); 1363 { 1364 art::ScopedObjectAccess soa(self); 1365 art::Runtime::Current()->GetClassLinker()->VisitClasses(&rcv); 1366 } 1367 1368 size_t size = rcv.classes_.size(); 1369 jclass* classes = nullptr; 1370 jvmtiError alloc_ret = env->Allocate(static_cast<jlong>(size * sizeof(jclass)), 1371 reinterpret_cast<unsigned char**>(&classes)); 1372 if (alloc_ret != ERR(NONE)) { 1373 return alloc_ret; 1374 } 1375 1376 for (size_t i = 0; i < size; ++i) { 1377 classes[i] = rcv.classes_[i]; 1378 } 1379 *classes_ptr = classes; 1380 *class_count_ptr = static_cast<jint>(size); 1381 1382 return ERR(NONE); 1383 } 1384 1385 jvmtiError HeapUtil::ForceGarbageCollection(jvmtiEnv* env ATTRIBUTE_UNUSED) { 1386 art::Runtime::Current()->GetHeap()->CollectGarbage(false); 1387 1388 return ERR(NONE); 1389 } 1390 1391 static constexpr jint kHeapIdDefault = 0; 1392 static constexpr jint kHeapIdImage = 1; 1393 static constexpr jint kHeapIdZygote = 2; 1394 static constexpr jint kHeapIdApp = 3; 1395 1396 static jint GetHeapId(art::ObjPtr<art::mirror::Object> obj) 1397 REQUIRES_SHARED(art::Locks::mutator_lock_) { 1398 if (obj == nullptr) { 1399 return -1; 1400 } 1401 1402 art::gc::Heap* const heap = art::Runtime::Current()->GetHeap(); 1403 const art::gc::space::ContinuousSpace* const space = 1404 heap->FindContinuousSpaceFromObject(obj, true); 1405 jint heap_type = kHeapIdApp; 1406 if (space != nullptr) { 1407 if (space->IsZygoteSpace()) { 1408 heap_type = kHeapIdZygote; 1409 } else if (space->IsImageSpace() && heap->ObjectIsInBootImageSpace(obj)) { 1410 // Only count objects in the boot image as HPROF_HEAP_IMAGE, this leaves app image objects 1411 // as HPROF_HEAP_APP. b/35762934 1412 heap_type = kHeapIdImage; 1413 } 1414 } else { 1415 const auto* los = heap->GetLargeObjectsSpace(); 1416 if (los->Contains(obj.Ptr()) && los->IsZygoteLargeObject(art::Thread::Current(), obj.Ptr())) { 1417 heap_type = kHeapIdZygote; 1418 } 1419 } 1420 return heap_type; 1421 }; 1422 1423 jvmtiError HeapExtensions::GetObjectHeapId(jvmtiEnv* env, jlong tag, jint* heap_id, ...) { 1424 if (heap_id == nullptr) { 1425 return ERR(NULL_POINTER); 1426 } 1427 1428 art::Thread* self = art::Thread::Current(); 1429 1430 auto work = [&]() REQUIRES_SHARED(art::Locks::mutator_lock_) { 1431 ObjectTagTable* tag_table = ArtJvmTiEnv::AsArtJvmTiEnv(env)->object_tag_table.get(); 1432 art::ObjPtr<art::mirror::Object> obj = tag_table->Find(tag); 1433 jint heap_type = GetHeapId(obj); 1434 if (heap_type == -1) { 1435 return ERR(NOT_FOUND); 1436 } 1437 *heap_id = heap_type; 1438 return ERR(NONE); 1439 }; 1440 1441 if (!art::Locks::mutator_lock_->IsSharedHeld(self)) { 1442 if (!self->IsThreadSuspensionAllowable()) { 1443 return ERR(INTERNAL); 1444 } 1445 art::ScopedObjectAccess soa(self); 1446 return work(); 1447 } else { 1448 // We cannot use SOA in this case. We might be holding the lock, but may not be in the 1449 // runnable state (e.g., during GC). 1450 art::Locks::mutator_lock_->AssertSharedHeld(self); 1451 // TODO: Investigate why ASSERT_SHARED_CAPABILITY doesn't work. 1452 auto annotalysis_workaround = [&]() NO_THREAD_SAFETY_ANALYSIS { 1453 return work(); 1454 }; 1455 return annotalysis_workaround(); 1456 } 1457 } 1458 1459 static jvmtiError CopyStringAndReturn(jvmtiEnv* env, const char* in, char** out) { 1460 jvmtiError error; 1461 JvmtiUniquePtr<char[]> param_name = CopyString(env, in, &error); 1462 if (param_name == nullptr) { 1463 return error; 1464 } 1465 *out = param_name.release(); 1466 return ERR(NONE); 1467 } 1468 1469 static constexpr const char* kHeapIdDefaultName = "default"; 1470 static constexpr const char* kHeapIdImageName = "image"; 1471 static constexpr const char* kHeapIdZygoteName = "zygote"; 1472 static constexpr const char* kHeapIdAppName = "app"; 1473 1474 jvmtiError HeapExtensions::GetHeapName(jvmtiEnv* env, jint heap_id, char** heap_name, ...) { 1475 switch (heap_id) { 1476 case kHeapIdDefault: 1477 return CopyStringAndReturn(env, kHeapIdDefaultName, heap_name); 1478 case kHeapIdImage: 1479 return CopyStringAndReturn(env, kHeapIdImageName, heap_name); 1480 case kHeapIdZygote: 1481 return CopyStringAndReturn(env, kHeapIdZygoteName, heap_name); 1482 case kHeapIdApp: 1483 return CopyStringAndReturn(env, kHeapIdAppName, heap_name); 1484 1485 default: 1486 return ERR(ILLEGAL_ARGUMENT); 1487 } 1488 } 1489 1490 jvmtiError HeapExtensions::IterateThroughHeapExt(jvmtiEnv* env, 1491 jint heap_filter, 1492 jclass klass, 1493 const jvmtiHeapCallbacks* callbacks, 1494 const void* user_data) { 1495 if (ArtJvmTiEnv::AsArtJvmTiEnv(env)->capabilities.can_tag_objects != 1) { \ 1496 return ERR(MUST_POSSESS_CAPABILITY); \ 1497 } 1498 1499 // ART extension API: Also pass the heap id. 1500 auto ArtIterateHeap = [](art::mirror::Object* obj, 1501 const jvmtiHeapCallbacks* cb_callbacks, 1502 jlong class_tag, 1503 jlong size, 1504 jlong* tag, 1505 jint length, 1506 void* cb_user_data) 1507 REQUIRES_SHARED(art::Locks::mutator_lock_) { 1508 jint heap_id = GetHeapId(obj); 1509 using ArtExtensionAPI = jint (*)(jlong, jlong, jlong*, jint length, void*, jint); 1510 return reinterpret_cast<ArtExtensionAPI>(cb_callbacks->heap_iteration_callback)( 1511 class_tag, size, tag, length, cb_user_data, heap_id); 1512 }; 1513 return DoIterateThroughHeap(ArtIterateHeap, 1514 env, 1515 ArtJvmTiEnv::AsArtJvmTiEnv(env)->object_tag_table.get(), 1516 heap_filter, 1517 klass, 1518 callbacks, 1519 user_data); 1520 } 1521 1522 } // namespace openjdkjvmti 1523