ART: Add primitive array reporting
Add support for array_primitive_value_callback.
Bug: 31385354
Test: m test-art-host-run-test-906-iterate-heap
Test: m test-art-host-run-test-913-heaps
Change-Id: I2d615295bc5ad3d2579170d152e5778f56bf12cb
diff --git a/runtime/openjdkjvmti/ti_heap.cc b/runtime/openjdkjvmti/ti_heap.cc
index 7efeea7..2fbc12b 100644
--- a/runtime/openjdkjvmti/ti_heap.cc
+++ b/runtime/openjdkjvmti/ti_heap.cc
@@ -31,6 +31,7 @@
#include "object_callbacks.h"
#include "object_tagging.h"
#include "obj_ptr-inl.h"
+#include "primitive.h"
#include "runtime.h"
#include "scoped_thread_state_change-inl.h"
#include "thread-inl.h"
@@ -89,6 +90,75 @@
return 0;
}
+// Report the contents of a primitive array, if a callback is set.
+jint ReportPrimitiveArray(art::ObjPtr<art::mirror::Object> obj,
+ jvmtiEnv* env,
+ ObjectTagTable* tag_table,
+ const jvmtiHeapCallbacks* cb,
+ const void* user_data) REQUIRES_SHARED(art::Locks::mutator_lock_) {
+ if (UNLIKELY(cb->array_primitive_value_callback != nullptr) &&
+ obj->IsArrayInstance() &&
+ !obj->IsObjectArray()) {
+ art::ObjPtr<art::mirror::Array> array = obj->AsArray();
+ int32_t array_length = array->GetLength();
+ size_t component_size = array->GetClass()->GetComponentSize();
+ art::Primitive::Type art_prim_type = array->GetClass()->GetComponentType()->GetPrimitiveType();
+ jvmtiPrimitiveType prim_type =
+ static_cast<jvmtiPrimitiveType>(art::Primitive::Descriptor(art_prim_type)[0]);
+ DCHECK(prim_type == JVMTI_PRIMITIVE_TYPE_BOOLEAN ||
+ prim_type == JVMTI_PRIMITIVE_TYPE_BYTE ||
+ prim_type == JVMTI_PRIMITIVE_TYPE_CHAR ||
+ prim_type == JVMTI_PRIMITIVE_TYPE_SHORT ||
+ prim_type == JVMTI_PRIMITIVE_TYPE_INT ||
+ prim_type == JVMTI_PRIMITIVE_TYPE_LONG ||
+ prim_type == JVMTI_PRIMITIVE_TYPE_FLOAT ||
+ prim_type == JVMTI_PRIMITIVE_TYPE_DOUBLE);
+
+ const jlong class_tag = tag_table->GetTagOrZero(obj->GetClass());
+ jlong array_tag = tag_table->GetTagOrZero(obj.Ptr());
+ const jlong saved_array_tag = array_tag;
+
+ jint result;
+ if (array_length == 0) {
+ result = cb->array_primitive_value_callback(class_tag,
+ obj->SizeOf(),
+ &array_tag,
+ 0,
+ prim_type,
+ nullptr,
+ const_cast<void*>(user_data));
+ } else {
+ jvmtiError alloc_error;
+ JvmtiUniquePtr<char[]> data = AllocJvmtiUniquePtr<char[]>(env,
+ array_length * component_size,
+ &alloc_error);
+ if (data == nullptr) {
+ // TODO: Not really sure what to do here. Should we abort the iteration and go all the way
+ // back? For now just warn.
+ LOG(WARNING) << "Unable to allocate buffer for array reporting! Silently dropping value.";
+ return 0;
+ }
+
+ memcpy(data.get(), array->GetRawData(component_size, 0), array_length * component_size);
+
+ result = cb->array_primitive_value_callback(class_tag,
+ obj->SizeOf(),
+ &array_tag,
+ array_length,
+ prim_type,
+ data.get(),
+ const_cast<void*>(user_data));
+ }
+
+ if (array_tag != saved_array_tag) {
+ tag_table->Set(obj.Ptr(), array_tag);
+ }
+
+ return result;
+ }
+ return 0;
+}
+
} // namespace
struct IterateThroughHeapData {
@@ -202,7 +272,15 @@
ithd->stop_reports = (string_ret & JVMTI_VISIT_ABORT) != 0;
}
- // TODO Implement array primitive callback.
+ if (!ithd->stop_reports) {
+ jint array_ret = ReportPrimitiveArray(obj,
+ ithd->env,
+ ithd->heap_util->GetTags(),
+ ithd->callbacks,
+ ithd->user_data);
+ ithd->stop_reports = (array_ret & JVMTI_VISIT_ABORT) != 0;
+ }
+
// TODO Implement primitive field callback.
}
@@ -215,11 +293,6 @@
return ERR(NULL_POINTER);
}
- if (callbacks->array_primitive_value_callback != nullptr) {
- // TODO: Implement.
- return ERR(NOT_IMPLEMENTED);
- }
-
art::Thread* self = art::Thread::Current();
art::ScopedObjectAccess soa(self); // Now we know we have the shared lock.
@@ -569,6 +642,11 @@
}
}
}
+ } else {
+ if (!stop_reports_) {
+ jint array_ret = ReportPrimitiveArray(array, env, tag_table_, callbacks_, user_data_);
+ stop_reports_ = (array_ret & JVMTI_VISIT_ABORT) != 0;
+ }
}
}
@@ -753,11 +831,6 @@
return ERR(NULL_POINTER);
}
- if (callbacks->array_primitive_value_callback != nullptr) {
- // TODO: Implement.
- return ERR(NOT_IMPLEMENTED);
- }
-
art::Thread* self = art::Thread::Current();
art::gc::Heap* heap = art::Runtime::Current()->GetHeap();