1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker * Copyright (C) 2016 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker *
4*795d594fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker *
8*795d594fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker *
10*795d594fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker */
16*795d594fSAndroid Build Coastguard Worker
17*795d594fSAndroid Build Coastguard Worker #include "ti_heap.h"
18*795d594fSAndroid Build Coastguard Worker
19*795d594fSAndroid Build Coastguard Worker #include <ios>
20*795d594fSAndroid Build Coastguard Worker #include <unordered_map>
21*795d594fSAndroid Build Coastguard Worker
22*795d594fSAndroid Build Coastguard Worker #include "android-base/logging.h"
23*795d594fSAndroid Build Coastguard Worker #include "android-base/thread_annotations.h"
24*795d594fSAndroid Build Coastguard Worker #include "arch/context.h"
25*795d594fSAndroid Build Coastguard Worker #include "art_field-inl.h"
26*795d594fSAndroid Build Coastguard Worker #include "art_jvmti.h"
27*795d594fSAndroid Build Coastguard Worker #include "base/logging.h"
28*795d594fSAndroid Build Coastguard Worker #include "base/macros.h"
29*795d594fSAndroid Build Coastguard Worker #include "base/mutex.h"
30*795d594fSAndroid Build Coastguard Worker #include "base/utils.h"
31*795d594fSAndroid Build Coastguard Worker #include "class_linker.h"
32*795d594fSAndroid Build Coastguard Worker #include "deopt_manager.h"
33*795d594fSAndroid Build Coastguard Worker #include "dex/primitive.h"
34*795d594fSAndroid Build Coastguard Worker #include "events-inl.h"
35*795d594fSAndroid Build Coastguard Worker #include "gc/collector_type.h"
36*795d594fSAndroid Build Coastguard Worker #include "gc/gc_cause.h"
37*795d594fSAndroid Build Coastguard Worker #include "gc/heap-visit-objects-inl.h"
38*795d594fSAndroid Build Coastguard Worker #include "gc/heap-inl.h"
39*795d594fSAndroid Build Coastguard Worker #include "gc/scoped_gc_critical_section.h"
40*795d594fSAndroid Build Coastguard Worker #include "gc_root-inl.h"
41*795d594fSAndroid Build Coastguard Worker #include "handle.h"
42*795d594fSAndroid Build Coastguard Worker #include "handle_scope.h"
43*795d594fSAndroid Build Coastguard Worker #include "java_frame_root_info.h"
44*795d594fSAndroid Build Coastguard Worker #include "jni/jni_env_ext.h"
45*795d594fSAndroid Build Coastguard Worker #include "jni/jni_id_manager.h"
46*795d594fSAndroid Build Coastguard Worker #include "jni/jni_internal.h"
47*795d594fSAndroid Build Coastguard Worker #include "jvmti_weak_table-inl.h"
48*795d594fSAndroid Build Coastguard Worker #include "mirror/array-inl.h"
49*795d594fSAndroid Build Coastguard Worker #include "mirror/array.h"
50*795d594fSAndroid Build Coastguard Worker #include "mirror/class.h"
51*795d594fSAndroid Build Coastguard Worker #include "mirror/object-inl.h"
52*795d594fSAndroid Build Coastguard Worker #include "mirror/object-refvisitor-inl.h"
53*795d594fSAndroid Build Coastguard Worker #include "mirror/object_array-inl.h"
54*795d594fSAndroid Build Coastguard Worker #include "mirror/object_array-alloc-inl.h"
55*795d594fSAndroid Build Coastguard Worker #include "mirror/object_reference.h"
56*795d594fSAndroid Build Coastguard Worker #include "obj_ptr-inl.h"
57*795d594fSAndroid Build Coastguard Worker #include "object_callbacks.h"
58*795d594fSAndroid Build Coastguard Worker #include "object_tagging.h"
59*795d594fSAndroid Build Coastguard Worker #include "offsets.h"
60*795d594fSAndroid Build Coastguard Worker #include "read_barrier.h"
61*795d594fSAndroid Build Coastguard Worker #include "runtime.h"
62*795d594fSAndroid Build Coastguard Worker #include "scoped_thread_state_change-inl.h"
63*795d594fSAndroid Build Coastguard Worker #include "stack.h"
64*795d594fSAndroid Build Coastguard Worker #include "thread-inl.h"
65*795d594fSAndroid Build Coastguard Worker #include "thread_list.h"
66*795d594fSAndroid Build Coastguard Worker #include "ti_logging.h"
67*795d594fSAndroid Build Coastguard Worker #include "ti_stack.h"
68*795d594fSAndroid Build Coastguard Worker #include "ti_thread.h"
69*795d594fSAndroid Build Coastguard Worker #include "well_known_classes.h"
70*795d594fSAndroid Build Coastguard Worker
71*795d594fSAndroid Build Coastguard Worker namespace openjdkjvmti {
72*795d594fSAndroid Build Coastguard Worker
73*795d594fSAndroid Build Coastguard Worker EventHandler* HeapExtensions::gEventHandler = nullptr;
74*795d594fSAndroid Build Coastguard Worker
75*795d594fSAndroid Build Coastguard Worker namespace {
76*795d594fSAndroid Build Coastguard Worker
77*795d594fSAndroid Build Coastguard Worker struct IndexCache {
78*795d594fSAndroid Build Coastguard Worker // The number of interface fields implemented by the class. This is a prefix to all assigned
79*795d594fSAndroid Build Coastguard Worker // field indices.
80*795d594fSAndroid Build Coastguard Worker size_t interface_fields;
81*795d594fSAndroid Build Coastguard Worker
82*795d594fSAndroid Build Coastguard Worker // It would be nice to also cache the following, but it is complicated to wire up into the
83*795d594fSAndroid Build Coastguard Worker // generic visit:
84*795d594fSAndroid Build Coastguard Worker // The number of fields in interfaces and superclasses. This is the first index assigned to
85*795d594fSAndroid Build Coastguard Worker // fields of the class.
86*795d594fSAndroid Build Coastguard Worker // size_t superclass_fields;
87*795d594fSAndroid Build Coastguard Worker };
88*795d594fSAndroid Build Coastguard Worker using IndexCachingTable = JvmtiWeakTable<IndexCache>;
89*795d594fSAndroid Build Coastguard Worker
90*795d594fSAndroid Build Coastguard Worker static IndexCachingTable gIndexCachingTable;
91*795d594fSAndroid Build Coastguard Worker
92*795d594fSAndroid Build Coastguard Worker // Report the contents of a string, if a callback is set.
ReportString(art::ObjPtr<art::mirror::Object> obj,jvmtiEnv * env,ObjectTagTable * tag_table,const jvmtiHeapCallbacks * cb,const void * user_data)93*795d594fSAndroid Build Coastguard Worker jint ReportString(art::ObjPtr<art::mirror::Object> obj,
94*795d594fSAndroid Build Coastguard Worker jvmtiEnv* env,
95*795d594fSAndroid Build Coastguard Worker ObjectTagTable* tag_table,
96*795d594fSAndroid Build Coastguard Worker const jvmtiHeapCallbacks* cb,
97*795d594fSAndroid Build Coastguard Worker const void* user_data) REQUIRES_SHARED(art::Locks::mutator_lock_) {
98*795d594fSAndroid Build Coastguard Worker if (UNLIKELY(cb->string_primitive_value_callback != nullptr) && obj->IsString()) {
99*795d594fSAndroid Build Coastguard Worker art::ObjPtr<art::mirror::String> str = obj->AsString();
100*795d594fSAndroid Build Coastguard Worker int32_t string_length = str->GetLength();
101*795d594fSAndroid Build Coastguard Worker JvmtiUniquePtr<uint16_t[]> data;
102*795d594fSAndroid Build Coastguard Worker
103*795d594fSAndroid Build Coastguard Worker if (string_length > 0) {
104*795d594fSAndroid Build Coastguard Worker jvmtiError alloc_error;
105*795d594fSAndroid Build Coastguard Worker data = AllocJvmtiUniquePtr<uint16_t[]>(env, string_length, &alloc_error);
106*795d594fSAndroid Build Coastguard Worker if (data == nullptr) {
107*795d594fSAndroid Build Coastguard Worker // TODO: Not really sure what to do here. Should we abort the iteration and go all the way
108*795d594fSAndroid Build Coastguard Worker // back? For now just warn.
109*795d594fSAndroid Build Coastguard Worker LOG(WARNING) << "Unable to allocate buffer for string reporting! Silently dropping value."
110*795d594fSAndroid Build Coastguard Worker << " >" << str->ToModifiedUtf8() << "<";
111*795d594fSAndroid Build Coastguard Worker return 0;
112*795d594fSAndroid Build Coastguard Worker }
113*795d594fSAndroid Build Coastguard Worker
114*795d594fSAndroid Build Coastguard Worker if (str->IsCompressed()) {
115*795d594fSAndroid Build Coastguard Worker uint8_t* compressed_data = str->GetValueCompressed();
116*795d594fSAndroid Build Coastguard Worker for (int32_t i = 0; i != string_length; ++i) {
117*795d594fSAndroid Build Coastguard Worker data[i] = compressed_data[i];
118*795d594fSAndroid Build Coastguard Worker }
119*795d594fSAndroid Build Coastguard Worker } else {
120*795d594fSAndroid Build Coastguard Worker // Can copy directly.
121*795d594fSAndroid Build Coastguard Worker memcpy(data.get(), str->GetValue(), string_length * sizeof(uint16_t));
122*795d594fSAndroid Build Coastguard Worker }
123*795d594fSAndroid Build Coastguard Worker }
124*795d594fSAndroid Build Coastguard Worker
125*795d594fSAndroid Build Coastguard Worker const jlong class_tag = tag_table->GetTagOrZero(obj->GetClass());
126*795d594fSAndroid Build Coastguard Worker jlong string_tag = tag_table->GetTagOrZero(obj.Ptr());
127*795d594fSAndroid Build Coastguard Worker const jlong saved_string_tag = string_tag;
128*795d594fSAndroid Build Coastguard Worker
129*795d594fSAndroid Build Coastguard Worker jint result = cb->string_primitive_value_callback(class_tag,
130*795d594fSAndroid Build Coastguard Worker obj->SizeOf(),
131*795d594fSAndroid Build Coastguard Worker &string_tag,
132*795d594fSAndroid Build Coastguard Worker data.get(),
133*795d594fSAndroid Build Coastguard Worker string_length,
134*795d594fSAndroid Build Coastguard Worker const_cast<void*>(user_data));
135*795d594fSAndroid Build Coastguard Worker if (string_tag != saved_string_tag) {
136*795d594fSAndroid Build Coastguard Worker tag_table->Set(obj.Ptr(), string_tag);
137*795d594fSAndroid Build Coastguard Worker }
138*795d594fSAndroid Build Coastguard Worker
139*795d594fSAndroid Build Coastguard Worker return result;
140*795d594fSAndroid Build Coastguard Worker }
141*795d594fSAndroid Build Coastguard Worker return 0;
142*795d594fSAndroid Build Coastguard Worker }
143*795d594fSAndroid Build Coastguard Worker
144*795d594fSAndroid Build Coastguard Worker // Report the contents of a primitive array, if a callback is set.
ReportPrimitiveArray(art::ObjPtr<art::mirror::Object> obj,jvmtiEnv * env,ObjectTagTable * tag_table,const jvmtiHeapCallbacks * cb,const void * user_data)145*795d594fSAndroid Build Coastguard Worker jint ReportPrimitiveArray(art::ObjPtr<art::mirror::Object> obj,
146*795d594fSAndroid Build Coastguard Worker jvmtiEnv* env,
147*795d594fSAndroid Build Coastguard Worker ObjectTagTable* tag_table,
148*795d594fSAndroid Build Coastguard Worker const jvmtiHeapCallbacks* cb,
149*795d594fSAndroid Build Coastguard Worker const void* user_data) REQUIRES_SHARED(art::Locks::mutator_lock_) {
150*795d594fSAndroid Build Coastguard Worker if (UNLIKELY(cb->array_primitive_value_callback != nullptr) &&
151*795d594fSAndroid Build Coastguard Worker obj->IsArrayInstance() &&
152*795d594fSAndroid Build Coastguard Worker !obj->IsObjectArray()) {
153*795d594fSAndroid Build Coastguard Worker art::ObjPtr<art::mirror::Array> array = obj->AsArray();
154*795d594fSAndroid Build Coastguard Worker int32_t array_length = array->GetLength();
155*795d594fSAndroid Build Coastguard Worker size_t component_size = array->GetClass()->GetComponentSize();
156*795d594fSAndroid Build Coastguard Worker art::Primitive::Type art_prim_type = array->GetClass()->GetComponentType()->GetPrimitiveType();
157*795d594fSAndroid Build Coastguard Worker jvmtiPrimitiveType prim_type =
158*795d594fSAndroid Build Coastguard Worker static_cast<jvmtiPrimitiveType>(art::Primitive::Descriptor(art_prim_type)[0]);
159*795d594fSAndroid Build Coastguard Worker DCHECK(prim_type == JVMTI_PRIMITIVE_TYPE_BOOLEAN ||
160*795d594fSAndroid Build Coastguard Worker prim_type == JVMTI_PRIMITIVE_TYPE_BYTE ||
161*795d594fSAndroid Build Coastguard Worker prim_type == JVMTI_PRIMITIVE_TYPE_CHAR ||
162*795d594fSAndroid Build Coastguard Worker prim_type == JVMTI_PRIMITIVE_TYPE_SHORT ||
163*795d594fSAndroid Build Coastguard Worker prim_type == JVMTI_PRIMITIVE_TYPE_INT ||
164*795d594fSAndroid Build Coastguard Worker prim_type == JVMTI_PRIMITIVE_TYPE_LONG ||
165*795d594fSAndroid Build Coastguard Worker prim_type == JVMTI_PRIMITIVE_TYPE_FLOAT ||
166*795d594fSAndroid Build Coastguard Worker prim_type == JVMTI_PRIMITIVE_TYPE_DOUBLE);
167*795d594fSAndroid Build Coastguard Worker
168*795d594fSAndroid Build Coastguard Worker const jlong class_tag = tag_table->GetTagOrZero(obj->GetClass());
169*795d594fSAndroid Build Coastguard Worker jlong array_tag = tag_table->GetTagOrZero(obj.Ptr());
170*795d594fSAndroid Build Coastguard Worker const jlong saved_array_tag = array_tag;
171*795d594fSAndroid Build Coastguard Worker
172*795d594fSAndroid Build Coastguard Worker jint result;
173*795d594fSAndroid Build Coastguard Worker if (array_length == 0) {
174*795d594fSAndroid Build Coastguard Worker result = cb->array_primitive_value_callback(class_tag,
175*795d594fSAndroid Build Coastguard Worker obj->SizeOf(),
176*795d594fSAndroid Build Coastguard Worker &array_tag,
177*795d594fSAndroid Build Coastguard Worker 0,
178*795d594fSAndroid Build Coastguard Worker prim_type,
179*795d594fSAndroid Build Coastguard Worker nullptr,
180*795d594fSAndroid Build Coastguard Worker const_cast<void*>(user_data));
181*795d594fSAndroid Build Coastguard Worker } else {
182*795d594fSAndroid Build Coastguard Worker jvmtiError alloc_error;
183*795d594fSAndroid Build Coastguard Worker JvmtiUniquePtr<char[]> data = AllocJvmtiUniquePtr<char[]>(env,
184*795d594fSAndroid Build Coastguard Worker array_length * component_size,
185*795d594fSAndroid Build Coastguard Worker &alloc_error);
186*795d594fSAndroid Build Coastguard Worker if (data == nullptr) {
187*795d594fSAndroid Build Coastguard Worker // TODO: Not really sure what to do here. Should we abort the iteration and go all the way
188*795d594fSAndroid Build Coastguard Worker // back? For now just warn.
189*795d594fSAndroid Build Coastguard Worker LOG(WARNING) << "Unable to allocate buffer for array reporting! Silently dropping value.";
190*795d594fSAndroid Build Coastguard Worker return 0;
191*795d594fSAndroid Build Coastguard Worker }
192*795d594fSAndroid Build Coastguard Worker
193*795d594fSAndroid Build Coastguard Worker memcpy(data.get(), array->GetRawData(component_size, 0), array_length * component_size);
194*795d594fSAndroid Build Coastguard Worker
195*795d594fSAndroid Build Coastguard Worker result = cb->array_primitive_value_callback(class_tag,
196*795d594fSAndroid Build Coastguard Worker obj->SizeOf(),
197*795d594fSAndroid Build Coastguard Worker &array_tag,
198*795d594fSAndroid Build Coastguard Worker array_length,
199*795d594fSAndroid Build Coastguard Worker prim_type,
200*795d594fSAndroid Build Coastguard Worker data.get(),
201*795d594fSAndroid Build Coastguard Worker const_cast<void*>(user_data));
202*795d594fSAndroid Build Coastguard Worker }
203*795d594fSAndroid Build Coastguard Worker
204*795d594fSAndroid Build Coastguard Worker if (array_tag != saved_array_tag) {
205*795d594fSAndroid Build Coastguard Worker tag_table->Set(obj.Ptr(), array_tag);
206*795d594fSAndroid Build Coastguard Worker }
207*795d594fSAndroid Build Coastguard Worker
208*795d594fSAndroid Build Coastguard Worker return result;
209*795d594fSAndroid Build Coastguard Worker }
210*795d594fSAndroid Build Coastguard Worker return 0;
211*795d594fSAndroid Build Coastguard Worker }
212*795d594fSAndroid Build Coastguard Worker
213*795d594fSAndroid Build Coastguard Worker template <typename UserData>
VisitorFalse(art::ObjPtr<art::mirror::Object> obj,art::ObjPtr<art::mirror::Class> klass,art::ArtField & field,size_t field_index,UserData * user_data)214*795d594fSAndroid Build Coastguard Worker bool VisitorFalse([[maybe_unused]] art::ObjPtr<art::mirror::Object> obj,
215*795d594fSAndroid Build Coastguard Worker [[maybe_unused]] art::ObjPtr<art::mirror::Class> klass,
216*795d594fSAndroid Build Coastguard Worker [[maybe_unused]] art::ArtField& field,
217*795d594fSAndroid Build Coastguard Worker [[maybe_unused]] size_t field_index,
218*795d594fSAndroid Build Coastguard Worker [[maybe_unused]] UserData* user_data) {
219*795d594fSAndroid Build Coastguard Worker return false;
220*795d594fSAndroid Build Coastguard Worker }
221*795d594fSAndroid Build Coastguard Worker
222*795d594fSAndroid Build Coastguard Worker template <typename UserData, bool kCallVisitorOnRecursion>
223*795d594fSAndroid Build Coastguard Worker class FieldVisitor {
224*795d594fSAndroid Build Coastguard Worker public:
225*795d594fSAndroid Build Coastguard Worker // Report the contents of a primitive fields of the given object, if a callback is set.
226*795d594fSAndroid Build Coastguard Worker template <typename StaticPrimitiveVisitor,
227*795d594fSAndroid Build Coastguard Worker typename StaticReferenceVisitor,
228*795d594fSAndroid Build Coastguard Worker typename InstancePrimitiveVisitor,
229*795d594fSAndroid Build Coastguard Worker typename InstanceReferenceVisitor>
ReportFields(art::ObjPtr<art::mirror::Object> obj,UserData * user_data,StaticPrimitiveVisitor & static_prim_visitor,StaticReferenceVisitor & static_ref_visitor,InstancePrimitiveVisitor & instance_prim_visitor,InstanceReferenceVisitor & instance_ref_visitor)230*795d594fSAndroid Build Coastguard Worker static bool ReportFields(art::ObjPtr<art::mirror::Object> obj,
231*795d594fSAndroid Build Coastguard Worker UserData* user_data,
232*795d594fSAndroid Build Coastguard Worker StaticPrimitiveVisitor& static_prim_visitor,
233*795d594fSAndroid Build Coastguard Worker StaticReferenceVisitor& static_ref_visitor,
234*795d594fSAndroid Build Coastguard Worker InstancePrimitiveVisitor& instance_prim_visitor,
235*795d594fSAndroid Build Coastguard Worker InstanceReferenceVisitor& instance_ref_visitor)
236*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(art::Locks::mutator_lock_) {
237*795d594fSAndroid Build Coastguard Worker FieldVisitor fv(user_data);
238*795d594fSAndroid Build Coastguard Worker
239*795d594fSAndroid Build Coastguard Worker if (obj->IsClass()) {
240*795d594fSAndroid Build Coastguard Worker // When visiting a class, we only visit the static fields of the given class. No field of
241*795d594fSAndroid Build Coastguard Worker // superclasses is visited.
242*795d594fSAndroid Build Coastguard Worker art::ObjPtr<art::mirror::Class> klass = obj->AsClass();
243*795d594fSAndroid Build Coastguard Worker // Only report fields on resolved classes. We need valid field data.
244*795d594fSAndroid Build Coastguard Worker if (!klass->IsResolved()) {
245*795d594fSAndroid Build Coastguard Worker return false;
246*795d594fSAndroid Build Coastguard Worker }
247*795d594fSAndroid Build Coastguard Worker return fv.ReportFieldsImpl(nullptr,
248*795d594fSAndroid Build Coastguard Worker obj->AsClass(),
249*795d594fSAndroid Build Coastguard Worker obj->AsClass()->IsInterface(),
250*795d594fSAndroid Build Coastguard Worker static_prim_visitor,
251*795d594fSAndroid Build Coastguard Worker static_ref_visitor,
252*795d594fSAndroid Build Coastguard Worker instance_prim_visitor,
253*795d594fSAndroid Build Coastguard Worker instance_ref_visitor);
254*795d594fSAndroid Build Coastguard Worker } else {
255*795d594fSAndroid Build Coastguard Worker // See comment above. Just double-checking here, but an instance *should* mean the class was
256*795d594fSAndroid Build Coastguard Worker // resolved.
257*795d594fSAndroid Build Coastguard Worker DCHECK(obj->GetClass()->IsResolved() || obj->GetClass()->IsErroneousResolved());
258*795d594fSAndroid Build Coastguard Worker return fv.ReportFieldsImpl(obj,
259*795d594fSAndroid Build Coastguard Worker obj->GetClass(),
260*795d594fSAndroid Build Coastguard Worker false,
261*795d594fSAndroid Build Coastguard Worker static_prim_visitor,
262*795d594fSAndroid Build Coastguard Worker static_ref_visitor,
263*795d594fSAndroid Build Coastguard Worker instance_prim_visitor,
264*795d594fSAndroid Build Coastguard Worker instance_ref_visitor);
265*795d594fSAndroid Build Coastguard Worker }
266*795d594fSAndroid Build Coastguard Worker }
267*795d594fSAndroid Build Coastguard Worker
268*795d594fSAndroid Build Coastguard Worker private:
FieldVisitor(UserData * user_data)269*795d594fSAndroid Build Coastguard Worker explicit FieldVisitor(UserData* user_data) : user_data_(user_data) {}
270*795d594fSAndroid Build Coastguard Worker
271*795d594fSAndroid Build Coastguard Worker // Report the contents of fields of the given object. If obj is null, report the static fields,
272*795d594fSAndroid Build Coastguard Worker // otherwise the instance fields.
273*795d594fSAndroid Build Coastguard Worker template <typename StaticPrimitiveVisitor,
274*795d594fSAndroid Build Coastguard Worker typename StaticReferenceVisitor,
275*795d594fSAndroid Build Coastguard Worker typename InstancePrimitiveVisitor,
276*795d594fSAndroid Build Coastguard Worker typename InstanceReferenceVisitor>
ReportFieldsImpl(art::ObjPtr<art::mirror::Object> obj,art::ObjPtr<art::mirror::Class> klass,bool skip_java_lang_object,StaticPrimitiveVisitor & static_prim_visitor,StaticReferenceVisitor & static_ref_visitor,InstancePrimitiveVisitor & instance_prim_visitor,InstanceReferenceVisitor & instance_ref_visitor)277*795d594fSAndroid Build Coastguard Worker bool ReportFieldsImpl(art::ObjPtr<art::mirror::Object> obj,
278*795d594fSAndroid Build Coastguard Worker art::ObjPtr<art::mirror::Class> klass,
279*795d594fSAndroid Build Coastguard Worker bool skip_java_lang_object,
280*795d594fSAndroid Build Coastguard Worker StaticPrimitiveVisitor& static_prim_visitor,
281*795d594fSAndroid Build Coastguard Worker StaticReferenceVisitor& static_ref_visitor,
282*795d594fSAndroid Build Coastguard Worker InstancePrimitiveVisitor& instance_prim_visitor,
283*795d594fSAndroid Build Coastguard Worker InstanceReferenceVisitor& instance_ref_visitor)
284*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(art::Locks::mutator_lock_) {
285*795d594fSAndroid Build Coastguard Worker // Compute the offset of field indices.
286*795d594fSAndroid Build Coastguard Worker size_t interface_field_count = CountInterfaceFields(klass);
287*795d594fSAndroid Build Coastguard Worker
288*795d594fSAndroid Build Coastguard Worker size_t tmp;
289*795d594fSAndroid Build Coastguard Worker bool aborted = ReportFieldsRecursive(obj,
290*795d594fSAndroid Build Coastguard Worker klass,
291*795d594fSAndroid Build Coastguard Worker interface_field_count,
292*795d594fSAndroid Build Coastguard Worker skip_java_lang_object,
293*795d594fSAndroid Build Coastguard Worker static_prim_visitor,
294*795d594fSAndroid Build Coastguard Worker static_ref_visitor,
295*795d594fSAndroid Build Coastguard Worker instance_prim_visitor,
296*795d594fSAndroid Build Coastguard Worker instance_ref_visitor,
297*795d594fSAndroid Build Coastguard Worker &tmp);
298*795d594fSAndroid Build Coastguard Worker return aborted;
299*795d594fSAndroid Build Coastguard Worker }
300*795d594fSAndroid Build Coastguard Worker
301*795d594fSAndroid Build Coastguard Worker // Visit primitive fields in an object (instance). Return true if the visit was aborted.
302*795d594fSAndroid Build Coastguard Worker template <typename StaticPrimitiveVisitor,
303*795d594fSAndroid Build Coastguard Worker typename StaticReferenceVisitor,
304*795d594fSAndroid Build Coastguard Worker typename InstancePrimitiveVisitor,
305*795d594fSAndroid Build Coastguard Worker typename InstanceReferenceVisitor>
ReportFieldsRecursive(art::ObjPtr<art::mirror::Object> obj,art::ObjPtr<art::mirror::Class> klass,size_t interface_fields,bool skip_java_lang_object,StaticPrimitiveVisitor & static_prim_visitor,StaticReferenceVisitor & static_ref_visitor,InstancePrimitiveVisitor & instance_prim_visitor,InstanceReferenceVisitor & instance_ref_visitor,size_t * field_index_out)306*795d594fSAndroid Build Coastguard Worker bool ReportFieldsRecursive(art::ObjPtr<art::mirror::Object> obj,
307*795d594fSAndroid Build Coastguard Worker art::ObjPtr<art::mirror::Class> klass,
308*795d594fSAndroid Build Coastguard Worker size_t interface_fields,
309*795d594fSAndroid Build Coastguard Worker bool skip_java_lang_object,
310*795d594fSAndroid Build Coastguard Worker StaticPrimitiveVisitor& static_prim_visitor,
311*795d594fSAndroid Build Coastguard Worker StaticReferenceVisitor& static_ref_visitor,
312*795d594fSAndroid Build Coastguard Worker InstancePrimitiveVisitor& instance_prim_visitor,
313*795d594fSAndroid Build Coastguard Worker InstanceReferenceVisitor& instance_ref_visitor,
314*795d594fSAndroid Build Coastguard Worker size_t* field_index_out)
315*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(art::Locks::mutator_lock_) {
316*795d594fSAndroid Build Coastguard Worker DCHECK(klass != nullptr);
317*795d594fSAndroid Build Coastguard Worker size_t field_index;
318*795d594fSAndroid Build Coastguard Worker if (klass->GetSuperClass() == nullptr) {
319*795d594fSAndroid Build Coastguard Worker // j.l.Object. Start with the fields from interfaces.
320*795d594fSAndroid Build Coastguard Worker field_index = interface_fields;
321*795d594fSAndroid Build Coastguard Worker if (skip_java_lang_object) {
322*795d594fSAndroid Build Coastguard Worker *field_index_out = field_index;
323*795d594fSAndroid Build Coastguard Worker return false;
324*795d594fSAndroid Build Coastguard Worker }
325*795d594fSAndroid Build Coastguard Worker } else {
326*795d594fSAndroid Build Coastguard Worker // Report superclass fields.
327*795d594fSAndroid Build Coastguard Worker if (kCallVisitorOnRecursion) {
328*795d594fSAndroid Build Coastguard Worker if (ReportFieldsRecursive(obj,
329*795d594fSAndroid Build Coastguard Worker klass->GetSuperClass(),
330*795d594fSAndroid Build Coastguard Worker interface_fields,
331*795d594fSAndroid Build Coastguard Worker skip_java_lang_object,
332*795d594fSAndroid Build Coastguard Worker static_prim_visitor,
333*795d594fSAndroid Build Coastguard Worker static_ref_visitor,
334*795d594fSAndroid Build Coastguard Worker instance_prim_visitor,
335*795d594fSAndroid Build Coastguard Worker instance_ref_visitor,
336*795d594fSAndroid Build Coastguard Worker &field_index)) {
337*795d594fSAndroid Build Coastguard Worker return true;
338*795d594fSAndroid Build Coastguard Worker }
339*795d594fSAndroid Build Coastguard Worker } else {
340*795d594fSAndroid Build Coastguard Worker // Still call, but with empty visitor. This is required for correct counting.
341*795d594fSAndroid Build Coastguard Worker ReportFieldsRecursive(obj,
342*795d594fSAndroid Build Coastguard Worker klass->GetSuperClass(),
343*795d594fSAndroid Build Coastguard Worker interface_fields,
344*795d594fSAndroid Build Coastguard Worker skip_java_lang_object,
345*795d594fSAndroid Build Coastguard Worker VisitorFalse<UserData>,
346*795d594fSAndroid Build Coastguard Worker VisitorFalse<UserData>,
347*795d594fSAndroid Build Coastguard Worker VisitorFalse<UserData>,
348*795d594fSAndroid Build Coastguard Worker VisitorFalse<UserData>,
349*795d594fSAndroid Build Coastguard Worker &field_index);
350*795d594fSAndroid Build Coastguard Worker }
351*795d594fSAndroid Build Coastguard Worker }
352*795d594fSAndroid Build Coastguard Worker
353*795d594fSAndroid Build Coastguard Worker // Now visit fields for the current klass.
354*795d594fSAndroid Build Coastguard Worker
355*795d594fSAndroid Build Coastguard Worker for (auto& static_field : klass->GetSFields()) {
356*795d594fSAndroid Build Coastguard Worker if (static_field.IsPrimitiveType()) {
357*795d594fSAndroid Build Coastguard Worker if (static_prim_visitor(obj,
358*795d594fSAndroid Build Coastguard Worker klass,
359*795d594fSAndroid Build Coastguard Worker static_field,
360*795d594fSAndroid Build Coastguard Worker field_index,
361*795d594fSAndroid Build Coastguard Worker user_data_)) {
362*795d594fSAndroid Build Coastguard Worker return true;
363*795d594fSAndroid Build Coastguard Worker }
364*795d594fSAndroid Build Coastguard Worker } else {
365*795d594fSAndroid Build Coastguard Worker if (static_ref_visitor(obj,
366*795d594fSAndroid Build Coastguard Worker klass,
367*795d594fSAndroid Build Coastguard Worker static_field,
368*795d594fSAndroid Build Coastguard Worker field_index,
369*795d594fSAndroid Build Coastguard Worker user_data_)) {
370*795d594fSAndroid Build Coastguard Worker return true;
371*795d594fSAndroid Build Coastguard Worker }
372*795d594fSAndroid Build Coastguard Worker }
373*795d594fSAndroid Build Coastguard Worker field_index++;
374*795d594fSAndroid Build Coastguard Worker }
375*795d594fSAndroid Build Coastguard Worker
376*795d594fSAndroid Build Coastguard Worker for (auto& instance_field : klass->GetIFields()) {
377*795d594fSAndroid Build Coastguard Worker if (instance_field.IsPrimitiveType()) {
378*795d594fSAndroid Build Coastguard Worker if (instance_prim_visitor(obj,
379*795d594fSAndroid Build Coastguard Worker klass,
380*795d594fSAndroid Build Coastguard Worker instance_field,
381*795d594fSAndroid Build Coastguard Worker field_index,
382*795d594fSAndroid Build Coastguard Worker user_data_)) {
383*795d594fSAndroid Build Coastguard Worker return true;
384*795d594fSAndroid Build Coastguard Worker }
385*795d594fSAndroid Build Coastguard Worker } else {
386*795d594fSAndroid Build Coastguard Worker if (instance_ref_visitor(obj,
387*795d594fSAndroid Build Coastguard Worker klass,
388*795d594fSAndroid Build Coastguard Worker instance_field,
389*795d594fSAndroid Build Coastguard Worker field_index,
390*795d594fSAndroid Build Coastguard Worker user_data_)) {
391*795d594fSAndroid Build Coastguard Worker return true;
392*795d594fSAndroid Build Coastguard Worker }
393*795d594fSAndroid Build Coastguard Worker }
394*795d594fSAndroid Build Coastguard Worker field_index++;
395*795d594fSAndroid Build Coastguard Worker }
396*795d594fSAndroid Build Coastguard Worker
397*795d594fSAndroid Build Coastguard Worker *field_index_out = field_index;
398*795d594fSAndroid Build Coastguard Worker return false;
399*795d594fSAndroid Build Coastguard Worker }
400*795d594fSAndroid Build Coastguard Worker
401*795d594fSAndroid Build Coastguard Worker // Implements a visit of the implemented interfaces of a given class.
402*795d594fSAndroid Build Coastguard Worker template <typename T>
403*795d594fSAndroid Build Coastguard Worker struct RecursiveInterfaceVisit {
VisitStaticopenjdkjvmti::__anon9790dd1d0111::FieldVisitor::RecursiveInterfaceVisit404*795d594fSAndroid Build Coastguard Worker static void VisitStatic(art::Thread* self, art::ObjPtr<art::mirror::Class> klass, T& visitor)
405*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(art::Locks::mutator_lock_) {
406*795d594fSAndroid Build Coastguard Worker RecursiveInterfaceVisit rv;
407*795d594fSAndroid Build Coastguard Worker rv.Visit(self, klass, visitor);
408*795d594fSAndroid Build Coastguard Worker }
409*795d594fSAndroid Build Coastguard Worker
Visitopenjdkjvmti::__anon9790dd1d0111::FieldVisitor::RecursiveInterfaceVisit410*795d594fSAndroid Build Coastguard Worker void Visit(art::Thread* self, art::ObjPtr<art::mirror::Class> klass, T& visitor)
411*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(art::Locks::mutator_lock_) {
412*795d594fSAndroid Build Coastguard Worker // First visit the parent, to get the order right.
413*795d594fSAndroid Build Coastguard Worker // (We do this in preparation for actual visiting of interface fields.)
414*795d594fSAndroid Build Coastguard Worker if (klass->GetSuperClass() != nullptr) {
415*795d594fSAndroid Build Coastguard Worker Visit(self, klass->GetSuperClass(), visitor);
416*795d594fSAndroid Build Coastguard Worker }
417*795d594fSAndroid Build Coastguard Worker for (uint32_t i = 0; i != klass->NumDirectInterfaces(); ++i) {
418*795d594fSAndroid Build Coastguard Worker art::ObjPtr<art::mirror::Class> inf_klass = klass->GetDirectInterface(i);
419*795d594fSAndroid Build Coastguard Worker DCHECK(inf_klass != nullptr);
420*795d594fSAndroid Build Coastguard Worker VisitInterface(self, inf_klass, visitor);
421*795d594fSAndroid Build Coastguard Worker }
422*795d594fSAndroid Build Coastguard Worker }
423*795d594fSAndroid Build Coastguard Worker
VisitInterfaceopenjdkjvmti::__anon9790dd1d0111::FieldVisitor::RecursiveInterfaceVisit424*795d594fSAndroid Build Coastguard Worker void VisitInterface(art::Thread* self, art::ObjPtr<art::mirror::Class> inf_klass, T& visitor)
425*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(art::Locks::mutator_lock_) {
426*795d594fSAndroid Build Coastguard Worker auto it = visited_interfaces.find(inf_klass.Ptr());
427*795d594fSAndroid Build Coastguard Worker if (it != visited_interfaces.end()) {
428*795d594fSAndroid Build Coastguard Worker return;
429*795d594fSAndroid Build Coastguard Worker }
430*795d594fSAndroid Build Coastguard Worker visited_interfaces.insert(inf_klass.Ptr());
431*795d594fSAndroid Build Coastguard Worker
432*795d594fSAndroid Build Coastguard Worker // Let the visitor know about this one. Note that this order is acceptable, as the ordering
433*795d594fSAndroid Build Coastguard Worker // of these fields never matters for known visitors.
434*795d594fSAndroid Build Coastguard Worker visitor(inf_klass);
435*795d594fSAndroid Build Coastguard Worker
436*795d594fSAndroid Build Coastguard Worker // Now visit the superinterfaces.
437*795d594fSAndroid Build Coastguard Worker for (uint32_t i = 0; i != inf_klass->NumDirectInterfaces(); ++i) {
438*795d594fSAndroid Build Coastguard Worker art::ObjPtr<art::mirror::Class> super_inf_klass = inf_klass->GetDirectInterface(i);
439*795d594fSAndroid Build Coastguard Worker DCHECK(super_inf_klass != nullptr);
440*795d594fSAndroid Build Coastguard Worker VisitInterface(self, super_inf_klass, visitor);
441*795d594fSAndroid Build Coastguard Worker }
442*795d594fSAndroid Build Coastguard Worker }
443*795d594fSAndroid Build Coastguard Worker
444*795d594fSAndroid Build Coastguard Worker std::unordered_set<art::mirror::Class*> visited_interfaces;
445*795d594fSAndroid Build Coastguard Worker };
446*795d594fSAndroid Build Coastguard Worker
447*795d594fSAndroid Build Coastguard Worker // Counting interface fields. Note that we cannot use the interface table, as that only contains
448*795d594fSAndroid Build Coastguard Worker // "non-marker" interfaces (= interfaces with methods).
CountInterfaceFields(art::ObjPtr<art::mirror::Class> klass)449*795d594fSAndroid Build Coastguard Worker static size_t CountInterfaceFields(art::ObjPtr<art::mirror::Class> klass)
450*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(art::Locks::mutator_lock_) {
451*795d594fSAndroid Build Coastguard Worker // Do we have a cached value?
452*795d594fSAndroid Build Coastguard Worker IndexCache tmp;
453*795d594fSAndroid Build Coastguard Worker if (gIndexCachingTable.GetTag(klass.Ptr(), &tmp)) {
454*795d594fSAndroid Build Coastguard Worker return tmp.interface_fields;
455*795d594fSAndroid Build Coastguard Worker }
456*795d594fSAndroid Build Coastguard Worker
457*795d594fSAndroid Build Coastguard Worker size_t count = 0;
458*795d594fSAndroid Build Coastguard Worker auto visitor = [&count](art::ObjPtr<art::mirror::Class> inf_klass)
459*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(art::Locks::mutator_lock_) {
460*795d594fSAndroid Build Coastguard Worker DCHECK(inf_klass->IsInterface());
461*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(0u, inf_klass->NumInstanceFields());
462*795d594fSAndroid Build Coastguard Worker count += inf_klass->NumStaticFields();
463*795d594fSAndroid Build Coastguard Worker };
464*795d594fSAndroid Build Coastguard Worker RecursiveInterfaceVisit<decltype(visitor)>::VisitStatic(art::Thread::Current(), klass, visitor);
465*795d594fSAndroid Build Coastguard Worker
466*795d594fSAndroid Build Coastguard Worker // Store this into the cache.
467*795d594fSAndroid Build Coastguard Worker tmp.interface_fields = count;
468*795d594fSAndroid Build Coastguard Worker gIndexCachingTable.Set(klass.Ptr(), tmp);
469*795d594fSAndroid Build Coastguard Worker
470*795d594fSAndroid Build Coastguard Worker return count;
471*795d594fSAndroid Build Coastguard Worker }
472*795d594fSAndroid Build Coastguard Worker
473*795d594fSAndroid Build Coastguard Worker UserData* user_data_;
474*795d594fSAndroid Build Coastguard Worker };
475*795d594fSAndroid Build Coastguard Worker
476*795d594fSAndroid Build Coastguard Worker // Debug helper. Prints the structure of an object.
477*795d594fSAndroid Build Coastguard Worker template <bool kStatic, bool kRef>
478*795d594fSAndroid Build Coastguard Worker struct DumpVisitor {
Callbackopenjdkjvmti::__anon9790dd1d0111::DumpVisitor479*795d594fSAndroid Build Coastguard Worker static bool Callback([[maybe_unused]] art::ObjPtr<art::mirror::Object> obj,
480*795d594fSAndroid Build Coastguard Worker [[maybe_unused]] art::ObjPtr<art::mirror::Class> klass,
481*795d594fSAndroid Build Coastguard Worker art::ArtField& field,
482*795d594fSAndroid Build Coastguard Worker size_t field_index,
483*795d594fSAndroid Build Coastguard Worker [[maybe_unused]] void* user_data)
484*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(art::Locks::mutator_lock_) {
485*795d594fSAndroid Build Coastguard Worker LOG(ERROR) << (kStatic ? "static " : "instance ")
486*795d594fSAndroid Build Coastguard Worker << (kRef ? "ref " : "primitive ")
487*795d594fSAndroid Build Coastguard Worker << field.PrettyField()
488*795d594fSAndroid Build Coastguard Worker << " @ "
489*795d594fSAndroid Build Coastguard Worker << field_index;
490*795d594fSAndroid Build Coastguard Worker return false;
491*795d594fSAndroid Build Coastguard Worker }
492*795d594fSAndroid Build Coastguard Worker };
DumpObjectFields(art::ObjPtr<art::mirror::Object> obj)493*795d594fSAndroid Build Coastguard Worker [[maybe_unused]] void DumpObjectFields(art::ObjPtr<art::mirror::Object> obj)
494*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(art::Locks::mutator_lock_) {
495*795d594fSAndroid Build Coastguard Worker if (obj->IsClass()) {
496*795d594fSAndroid Build Coastguard Worker FieldVisitor<void, false>:: ReportFields(obj,
497*795d594fSAndroid Build Coastguard Worker nullptr,
498*795d594fSAndroid Build Coastguard Worker DumpVisitor<true, false>::Callback,
499*795d594fSAndroid Build Coastguard Worker DumpVisitor<true, true>::Callback,
500*795d594fSAndroid Build Coastguard Worker DumpVisitor<false, false>::Callback,
501*795d594fSAndroid Build Coastguard Worker DumpVisitor<false, true>::Callback);
502*795d594fSAndroid Build Coastguard Worker } else {
503*795d594fSAndroid Build Coastguard Worker FieldVisitor<void, true>::ReportFields(obj,
504*795d594fSAndroid Build Coastguard Worker nullptr,
505*795d594fSAndroid Build Coastguard Worker DumpVisitor<true, false>::Callback,
506*795d594fSAndroid Build Coastguard Worker DumpVisitor<true, true>::Callback,
507*795d594fSAndroid Build Coastguard Worker DumpVisitor<false, false>::Callback,
508*795d594fSAndroid Build Coastguard Worker DumpVisitor<false, true>::Callback);
509*795d594fSAndroid Build Coastguard Worker }
510*795d594fSAndroid Build Coastguard Worker }
511*795d594fSAndroid Build Coastguard Worker
512*795d594fSAndroid Build Coastguard Worker class ReportPrimitiveField {
513*795d594fSAndroid Build Coastguard Worker public:
Report(art::ObjPtr<art::mirror::Object> obj,ObjectTagTable * tag_table,const jvmtiHeapCallbacks * cb,const void * user_data)514*795d594fSAndroid Build Coastguard Worker static bool Report(art::ObjPtr<art::mirror::Object> obj,
515*795d594fSAndroid Build Coastguard Worker ObjectTagTable* tag_table,
516*795d594fSAndroid Build Coastguard Worker const jvmtiHeapCallbacks* cb,
517*795d594fSAndroid Build Coastguard Worker const void* user_data)
518*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(art::Locks::mutator_lock_) {
519*795d594fSAndroid Build Coastguard Worker if (UNLIKELY(cb->primitive_field_callback != nullptr)) {
520*795d594fSAndroid Build Coastguard Worker jlong class_tag = tag_table->GetTagOrZero(obj->GetClass());
521*795d594fSAndroid Build Coastguard Worker ReportPrimitiveField rpf(tag_table, class_tag, cb, user_data);
522*795d594fSAndroid Build Coastguard Worker if (obj->IsClass()) {
523*795d594fSAndroid Build Coastguard Worker return FieldVisitor<ReportPrimitiveField, false>::ReportFields(
524*795d594fSAndroid Build Coastguard Worker obj,
525*795d594fSAndroid Build Coastguard Worker &rpf,
526*795d594fSAndroid Build Coastguard Worker ReportPrimitiveFieldCallback<true>,
527*795d594fSAndroid Build Coastguard Worker VisitorFalse<ReportPrimitiveField>,
528*795d594fSAndroid Build Coastguard Worker VisitorFalse<ReportPrimitiveField>,
529*795d594fSAndroid Build Coastguard Worker VisitorFalse<ReportPrimitiveField>);
530*795d594fSAndroid Build Coastguard Worker } else {
531*795d594fSAndroid Build Coastguard Worker return FieldVisitor<ReportPrimitiveField, true>::ReportFields(
532*795d594fSAndroid Build Coastguard Worker obj,
533*795d594fSAndroid Build Coastguard Worker &rpf,
534*795d594fSAndroid Build Coastguard Worker VisitorFalse<ReportPrimitiveField>,
535*795d594fSAndroid Build Coastguard Worker VisitorFalse<ReportPrimitiveField>,
536*795d594fSAndroid Build Coastguard Worker ReportPrimitiveFieldCallback<false>,
537*795d594fSAndroid Build Coastguard Worker VisitorFalse<ReportPrimitiveField>);
538*795d594fSAndroid Build Coastguard Worker }
539*795d594fSAndroid Build Coastguard Worker }
540*795d594fSAndroid Build Coastguard Worker return false;
541*795d594fSAndroid Build Coastguard Worker }
542*795d594fSAndroid Build Coastguard Worker
543*795d594fSAndroid Build Coastguard Worker
544*795d594fSAndroid Build Coastguard Worker private:
ReportPrimitiveField(ObjectTagTable * tag_table,jlong class_tag,const jvmtiHeapCallbacks * cb,const void * user_data)545*795d594fSAndroid Build Coastguard Worker ReportPrimitiveField(ObjectTagTable* tag_table,
546*795d594fSAndroid Build Coastguard Worker jlong class_tag,
547*795d594fSAndroid Build Coastguard Worker const jvmtiHeapCallbacks* cb,
548*795d594fSAndroid Build Coastguard Worker const void* user_data)
549*795d594fSAndroid Build Coastguard Worker : tag_table_(tag_table), class_tag_(class_tag), cb_(cb), user_data_(user_data) {}
550*795d594fSAndroid Build Coastguard Worker
551*795d594fSAndroid Build Coastguard Worker template <bool kReportStatic>
ReportPrimitiveFieldCallback(art::ObjPtr<art::mirror::Object> obj,art::ObjPtr<art::mirror::Class> klass,art::ArtField & field,size_t field_index,ReportPrimitiveField * user_data)552*795d594fSAndroid Build Coastguard Worker static bool ReportPrimitiveFieldCallback(art::ObjPtr<art::mirror::Object> obj,
553*795d594fSAndroid Build Coastguard Worker art::ObjPtr<art::mirror::Class> klass,
554*795d594fSAndroid Build Coastguard Worker art::ArtField& field,
555*795d594fSAndroid Build Coastguard Worker size_t field_index,
556*795d594fSAndroid Build Coastguard Worker ReportPrimitiveField* user_data)
557*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(art::Locks::mutator_lock_) {
558*795d594fSAndroid Build Coastguard Worker art::Primitive::Type art_prim_type = field.GetTypeAsPrimitiveType();
559*795d594fSAndroid Build Coastguard Worker jvmtiPrimitiveType prim_type =
560*795d594fSAndroid Build Coastguard Worker static_cast<jvmtiPrimitiveType>(art::Primitive::Descriptor(art_prim_type)[0]);
561*795d594fSAndroid Build Coastguard Worker DCHECK(prim_type == JVMTI_PRIMITIVE_TYPE_BOOLEAN ||
562*795d594fSAndroid Build Coastguard Worker prim_type == JVMTI_PRIMITIVE_TYPE_BYTE ||
563*795d594fSAndroid Build Coastguard Worker prim_type == JVMTI_PRIMITIVE_TYPE_CHAR ||
564*795d594fSAndroid Build Coastguard Worker prim_type == JVMTI_PRIMITIVE_TYPE_SHORT ||
565*795d594fSAndroid Build Coastguard Worker prim_type == JVMTI_PRIMITIVE_TYPE_INT ||
566*795d594fSAndroid Build Coastguard Worker prim_type == JVMTI_PRIMITIVE_TYPE_LONG ||
567*795d594fSAndroid Build Coastguard Worker prim_type == JVMTI_PRIMITIVE_TYPE_FLOAT ||
568*795d594fSAndroid Build Coastguard Worker prim_type == JVMTI_PRIMITIVE_TYPE_DOUBLE);
569*795d594fSAndroid Build Coastguard Worker jvmtiHeapReferenceInfo info;
570*795d594fSAndroid Build Coastguard Worker info.field.index = field_index;
571*795d594fSAndroid Build Coastguard Worker
572*795d594fSAndroid Build Coastguard Worker jvalue value;
573*795d594fSAndroid Build Coastguard Worker memset(&value, 0, sizeof(jvalue));
574*795d594fSAndroid Build Coastguard Worker art::ObjPtr<art::mirror::Object> src = kReportStatic ? klass : obj;
575*795d594fSAndroid Build Coastguard Worker switch (art_prim_type) {
576*795d594fSAndroid Build Coastguard Worker case art::Primitive::Type::kPrimBoolean:
577*795d594fSAndroid Build Coastguard Worker value.z = field.GetBoolean(src) == 0 ? JNI_FALSE : JNI_TRUE;
578*795d594fSAndroid Build Coastguard Worker break;
579*795d594fSAndroid Build Coastguard Worker case art::Primitive::Type::kPrimByte:
580*795d594fSAndroid Build Coastguard Worker value.b = field.GetByte(src);
581*795d594fSAndroid Build Coastguard Worker break;
582*795d594fSAndroid Build Coastguard Worker case art::Primitive::Type::kPrimChar:
583*795d594fSAndroid Build Coastguard Worker value.c = field.GetChar(src);
584*795d594fSAndroid Build Coastguard Worker break;
585*795d594fSAndroid Build Coastguard Worker case art::Primitive::Type::kPrimShort:
586*795d594fSAndroid Build Coastguard Worker value.s = field.GetShort(src);
587*795d594fSAndroid Build Coastguard Worker break;
588*795d594fSAndroid Build Coastguard Worker case art::Primitive::Type::kPrimInt:
589*795d594fSAndroid Build Coastguard Worker value.i = field.GetInt(src);
590*795d594fSAndroid Build Coastguard Worker break;
591*795d594fSAndroid Build Coastguard Worker case art::Primitive::Type::kPrimLong:
592*795d594fSAndroid Build Coastguard Worker value.j = field.GetLong(src);
593*795d594fSAndroid Build Coastguard Worker break;
594*795d594fSAndroid Build Coastguard Worker case art::Primitive::Type::kPrimFloat:
595*795d594fSAndroid Build Coastguard Worker value.f = field.GetFloat(src);
596*795d594fSAndroid Build Coastguard Worker break;
597*795d594fSAndroid Build Coastguard Worker case art::Primitive::Type::kPrimDouble:
598*795d594fSAndroid Build Coastguard Worker value.d = field.GetDouble(src);
599*795d594fSAndroid Build Coastguard Worker break;
600*795d594fSAndroid Build Coastguard Worker case art::Primitive::Type::kPrimVoid:
601*795d594fSAndroid Build Coastguard Worker case art::Primitive::Type::kPrimNot: {
602*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Should not reach here";
603*795d594fSAndroid Build Coastguard Worker UNREACHABLE();
604*795d594fSAndroid Build Coastguard Worker }
605*795d594fSAndroid Build Coastguard Worker }
606*795d594fSAndroid Build Coastguard Worker
607*795d594fSAndroid Build Coastguard Worker jlong obj_tag = user_data->tag_table_->GetTagOrZero(src.Ptr());
608*795d594fSAndroid Build Coastguard Worker const jlong saved_obj_tag = obj_tag;
609*795d594fSAndroid Build Coastguard Worker
610*795d594fSAndroid Build Coastguard Worker jint ret = user_data->cb_->primitive_field_callback(kReportStatic
611*795d594fSAndroid Build Coastguard Worker ? JVMTI_HEAP_REFERENCE_STATIC_FIELD
612*795d594fSAndroid Build Coastguard Worker : JVMTI_HEAP_REFERENCE_FIELD,
613*795d594fSAndroid Build Coastguard Worker &info,
614*795d594fSAndroid Build Coastguard Worker user_data->class_tag_,
615*795d594fSAndroid Build Coastguard Worker &obj_tag,
616*795d594fSAndroid Build Coastguard Worker value,
617*795d594fSAndroid Build Coastguard Worker prim_type,
618*795d594fSAndroid Build Coastguard Worker const_cast<void*>(user_data->user_data_));
619*795d594fSAndroid Build Coastguard Worker
620*795d594fSAndroid Build Coastguard Worker if (saved_obj_tag != obj_tag) {
621*795d594fSAndroid Build Coastguard Worker user_data->tag_table_->Set(src.Ptr(), obj_tag);
622*795d594fSAndroid Build Coastguard Worker }
623*795d594fSAndroid Build Coastguard Worker
624*795d594fSAndroid Build Coastguard Worker if ((ret & JVMTI_VISIT_ABORT) != 0) {
625*795d594fSAndroid Build Coastguard Worker return true;
626*795d594fSAndroid Build Coastguard Worker }
627*795d594fSAndroid Build Coastguard Worker
628*795d594fSAndroid Build Coastguard Worker return false;
629*795d594fSAndroid Build Coastguard Worker }
630*795d594fSAndroid Build Coastguard Worker
631*795d594fSAndroid Build Coastguard Worker ObjectTagTable* tag_table_;
632*795d594fSAndroid Build Coastguard Worker jlong class_tag_;
633*795d594fSAndroid Build Coastguard Worker const jvmtiHeapCallbacks* cb_;
634*795d594fSAndroid Build Coastguard Worker const void* user_data_;
635*795d594fSAndroid Build Coastguard Worker };
636*795d594fSAndroid Build Coastguard Worker
637*795d594fSAndroid Build Coastguard Worker struct HeapFilter {
HeapFilteropenjdkjvmti::__anon9790dd1d0111::HeapFilter638*795d594fSAndroid Build Coastguard Worker explicit HeapFilter(jint heap_filter)
639*795d594fSAndroid Build Coastguard Worker : filter_out_tagged((heap_filter & JVMTI_HEAP_FILTER_TAGGED) != 0),
640*795d594fSAndroid Build Coastguard Worker filter_out_untagged((heap_filter & JVMTI_HEAP_FILTER_UNTAGGED) != 0),
641*795d594fSAndroid Build Coastguard Worker filter_out_class_tagged((heap_filter & JVMTI_HEAP_FILTER_CLASS_TAGGED) != 0),
642*795d594fSAndroid Build Coastguard Worker filter_out_class_untagged((heap_filter & JVMTI_HEAP_FILTER_CLASS_UNTAGGED) != 0),
643*795d594fSAndroid Build Coastguard Worker any_filter(filter_out_tagged ||
644*795d594fSAndroid Build Coastguard Worker filter_out_untagged ||
645*795d594fSAndroid Build Coastguard Worker filter_out_class_tagged ||
646*795d594fSAndroid Build Coastguard Worker filter_out_class_untagged) {
647*795d594fSAndroid Build Coastguard Worker }
648*795d594fSAndroid Build Coastguard Worker
ShouldReportByHeapFilteropenjdkjvmti::__anon9790dd1d0111::HeapFilter649*795d594fSAndroid Build Coastguard Worker bool ShouldReportByHeapFilter(jlong tag, jlong class_tag) const {
650*795d594fSAndroid Build Coastguard Worker if (!any_filter) {
651*795d594fSAndroid Build Coastguard Worker return true;
652*795d594fSAndroid Build Coastguard Worker }
653*795d594fSAndroid Build Coastguard Worker
654*795d594fSAndroid Build Coastguard Worker if ((tag == 0 && filter_out_untagged) || (tag != 0 && filter_out_tagged)) {
655*795d594fSAndroid Build Coastguard Worker return false;
656*795d594fSAndroid Build Coastguard Worker }
657*795d594fSAndroid Build Coastguard Worker
658*795d594fSAndroid Build Coastguard Worker if ((class_tag == 0 && filter_out_class_untagged) ||
659*795d594fSAndroid Build Coastguard Worker (class_tag != 0 && filter_out_class_tagged)) {
660*795d594fSAndroid Build Coastguard Worker return false;
661*795d594fSAndroid Build Coastguard Worker }
662*795d594fSAndroid Build Coastguard Worker
663*795d594fSAndroid Build Coastguard Worker return true;
664*795d594fSAndroid Build Coastguard Worker }
665*795d594fSAndroid Build Coastguard Worker
666*795d594fSAndroid Build Coastguard Worker const bool filter_out_tagged;
667*795d594fSAndroid Build Coastguard Worker const bool filter_out_untagged;
668*795d594fSAndroid Build Coastguard Worker const bool filter_out_class_tagged;
669*795d594fSAndroid Build Coastguard Worker const bool filter_out_class_untagged;
670*795d594fSAndroid Build Coastguard Worker const bool any_filter;
671*795d594fSAndroid Build Coastguard Worker };
672*795d594fSAndroid Build Coastguard Worker
673*795d594fSAndroid Build Coastguard Worker } // namespace
674*795d594fSAndroid Build Coastguard Worker
Register()675*795d594fSAndroid Build Coastguard Worker void HeapUtil::Register() {
676*795d594fSAndroid Build Coastguard Worker art::Runtime::Current()->AddSystemWeakHolder(&gIndexCachingTable);
677*795d594fSAndroid Build Coastguard Worker }
678*795d594fSAndroid Build Coastguard Worker
Unregister()679*795d594fSAndroid Build Coastguard Worker void HeapUtil::Unregister() {
680*795d594fSAndroid Build Coastguard Worker art::Runtime::Current()->RemoveSystemWeakHolder(&gIndexCachingTable);
681*795d594fSAndroid Build Coastguard Worker }
682*795d594fSAndroid Build Coastguard Worker
IterateOverInstancesOfClass(jvmtiEnv * env,jclass klass,jvmtiHeapObjectFilter filter,jvmtiHeapObjectCallback cb,const void * user_data)683*795d594fSAndroid Build Coastguard Worker jvmtiError HeapUtil::IterateOverInstancesOfClass(jvmtiEnv* env,
684*795d594fSAndroid Build Coastguard Worker jclass klass,
685*795d594fSAndroid Build Coastguard Worker jvmtiHeapObjectFilter filter,
686*795d594fSAndroid Build Coastguard Worker jvmtiHeapObjectCallback cb,
687*795d594fSAndroid Build Coastguard Worker const void* user_data) {
688*795d594fSAndroid Build Coastguard Worker if (cb == nullptr || klass == nullptr) {
689*795d594fSAndroid Build Coastguard Worker return ERR(NULL_POINTER);
690*795d594fSAndroid Build Coastguard Worker }
691*795d594fSAndroid Build Coastguard Worker
692*795d594fSAndroid Build Coastguard Worker art::Thread* self = art::Thread::Current();
693*795d594fSAndroid Build Coastguard Worker art::ScopedObjectAccess soa(self); // Now we know we have the shared lock.
694*795d594fSAndroid Build Coastguard Worker art::StackHandleScope<1> hs(self);
695*795d594fSAndroid Build Coastguard Worker
696*795d594fSAndroid Build Coastguard Worker art::ObjPtr<art::mirror::Object> klass_ptr(soa.Decode<art::mirror::Class>(klass));
697*795d594fSAndroid Build Coastguard Worker if (!klass_ptr->IsClass()) {
698*795d594fSAndroid Build Coastguard Worker return ERR(INVALID_CLASS);
699*795d594fSAndroid Build Coastguard Worker }
700*795d594fSAndroid Build Coastguard Worker art::Handle<art::mirror::Class> filter_klass(hs.NewHandle(klass_ptr->AsClass()));
701*795d594fSAndroid Build Coastguard Worker ObjectTagTable* tag_table = ArtJvmTiEnv::AsArtJvmTiEnv(env)->object_tag_table.get();
702*795d594fSAndroid Build Coastguard Worker bool stop_reports = false;
703*795d594fSAndroid Build Coastguard Worker auto visitor = [&](art::mirror::Object* obj) REQUIRES_SHARED(art::Locks::mutator_lock_) {
704*795d594fSAndroid Build Coastguard Worker // Early return, as we can't really stop visiting.
705*795d594fSAndroid Build Coastguard Worker if (stop_reports) {
706*795d594fSAndroid Build Coastguard Worker return;
707*795d594fSAndroid Build Coastguard Worker }
708*795d594fSAndroid Build Coastguard Worker
709*795d594fSAndroid Build Coastguard Worker art::ScopedAssertNoThreadSuspension no_suspension("IterateOverInstancesOfClass");
710*795d594fSAndroid Build Coastguard Worker
711*795d594fSAndroid Build Coastguard Worker art::ObjPtr<art::mirror::Class> klass = obj->GetClass();
712*795d594fSAndroid Build Coastguard Worker
713*795d594fSAndroid Build Coastguard Worker if (filter_klass != nullptr && !filter_klass->IsAssignableFrom(klass)) {
714*795d594fSAndroid Build Coastguard Worker return;
715*795d594fSAndroid Build Coastguard Worker }
716*795d594fSAndroid Build Coastguard Worker
717*795d594fSAndroid Build Coastguard Worker jlong tag = 0;
718*795d594fSAndroid Build Coastguard Worker tag_table->GetTag(obj, &tag);
719*795d594fSAndroid Build Coastguard Worker if ((filter != JVMTI_HEAP_OBJECT_EITHER) &&
720*795d594fSAndroid Build Coastguard Worker ((tag == 0 && filter == JVMTI_HEAP_OBJECT_TAGGED) ||
721*795d594fSAndroid Build Coastguard Worker (tag != 0 && filter == JVMTI_HEAP_OBJECT_UNTAGGED))) {
722*795d594fSAndroid Build Coastguard Worker return;
723*795d594fSAndroid Build Coastguard Worker }
724*795d594fSAndroid Build Coastguard Worker
725*795d594fSAndroid Build Coastguard Worker jlong class_tag = 0;
726*795d594fSAndroid Build Coastguard Worker tag_table->GetTag(klass.Ptr(), &class_tag);
727*795d594fSAndroid Build Coastguard Worker
728*795d594fSAndroid Build Coastguard Worker jlong saved_tag = tag;
729*795d594fSAndroid Build Coastguard Worker jint ret = cb(class_tag, obj->SizeOf(), &tag, const_cast<void*>(user_data));
730*795d594fSAndroid Build Coastguard Worker
731*795d594fSAndroid Build Coastguard Worker stop_reports = (ret == JVMTI_ITERATION_ABORT);
732*795d594fSAndroid Build Coastguard Worker
733*795d594fSAndroid Build Coastguard Worker if (tag != saved_tag) {
734*795d594fSAndroid Build Coastguard Worker tag_table->Set(obj, tag);
735*795d594fSAndroid Build Coastguard Worker }
736*795d594fSAndroid Build Coastguard Worker };
737*795d594fSAndroid Build Coastguard Worker art::Runtime::Current()->GetHeap()->VisitObjects(visitor);
738*795d594fSAndroid Build Coastguard Worker
739*795d594fSAndroid Build Coastguard Worker return OK;
740*795d594fSAndroid Build Coastguard Worker }
741*795d594fSAndroid Build Coastguard Worker
742*795d594fSAndroid Build Coastguard Worker template <typename T>
DoIterateThroughHeap(T fn,jvmtiEnv * env,ObjectTagTable * tag_table,jint heap_filter_int,jclass klass,const jvmtiHeapCallbacks * callbacks,const void * user_data)743*795d594fSAndroid Build Coastguard Worker static jvmtiError DoIterateThroughHeap(T fn,
744*795d594fSAndroid Build Coastguard Worker jvmtiEnv* env,
745*795d594fSAndroid Build Coastguard Worker ObjectTagTable* tag_table,
746*795d594fSAndroid Build Coastguard Worker jint heap_filter_int,
747*795d594fSAndroid Build Coastguard Worker jclass klass,
748*795d594fSAndroid Build Coastguard Worker const jvmtiHeapCallbacks* callbacks,
749*795d594fSAndroid Build Coastguard Worker const void* user_data) {
750*795d594fSAndroid Build Coastguard Worker if (callbacks == nullptr) {
751*795d594fSAndroid Build Coastguard Worker return ERR(NULL_POINTER);
752*795d594fSAndroid Build Coastguard Worker }
753*795d594fSAndroid Build Coastguard Worker
754*795d594fSAndroid Build Coastguard Worker art::Thread* self = art::Thread::Current();
755*795d594fSAndroid Build Coastguard Worker art::ScopedObjectAccess soa(self); // Now we know we have the shared lock.
756*795d594fSAndroid Build Coastguard Worker
757*795d594fSAndroid Build Coastguard Worker bool stop_reports = false;
758*795d594fSAndroid Build Coastguard Worker const HeapFilter heap_filter(heap_filter_int);
759*795d594fSAndroid Build Coastguard Worker art::StackHandleScope<1> hs(self);
760*795d594fSAndroid Build Coastguard Worker art::Handle<art::mirror::Class> filter_klass(hs.NewHandle(soa.Decode<art::mirror::Class>(klass)));
761*795d594fSAndroid Build Coastguard Worker auto visitor = [&](art::mirror::Object* obj) REQUIRES_SHARED(art::Locks::mutator_lock_) {
762*795d594fSAndroid Build Coastguard Worker // Early return, as we can't really stop visiting.
763*795d594fSAndroid Build Coastguard Worker if (stop_reports) {
764*795d594fSAndroid Build Coastguard Worker return;
765*795d594fSAndroid Build Coastguard Worker }
766*795d594fSAndroid Build Coastguard Worker
767*795d594fSAndroid Build Coastguard Worker art::ScopedAssertNoThreadSuspension no_suspension("IterateThroughHeapCallback");
768*795d594fSAndroid Build Coastguard Worker
769*795d594fSAndroid Build Coastguard Worker jlong tag = 0;
770*795d594fSAndroid Build Coastguard Worker tag_table->GetTag(obj, &tag);
771*795d594fSAndroid Build Coastguard Worker
772*795d594fSAndroid Build Coastguard Worker jlong class_tag = 0;
773*795d594fSAndroid Build Coastguard Worker art::ObjPtr<art::mirror::Class> klass = obj->GetClass();
774*795d594fSAndroid Build Coastguard Worker tag_table->GetTag(klass.Ptr(), &class_tag);
775*795d594fSAndroid Build Coastguard Worker // For simplicity, even if we find a tag = 0, assume 0 = not tagged.
776*795d594fSAndroid Build Coastguard Worker
777*795d594fSAndroid Build Coastguard Worker if (!heap_filter.ShouldReportByHeapFilter(tag, class_tag)) {
778*795d594fSAndroid Build Coastguard Worker return;
779*795d594fSAndroid Build Coastguard Worker }
780*795d594fSAndroid Build Coastguard Worker
781*795d594fSAndroid Build Coastguard Worker if (filter_klass != nullptr) {
782*795d594fSAndroid Build Coastguard Worker if (filter_klass.Get() != klass) {
783*795d594fSAndroid Build Coastguard Worker return;
784*795d594fSAndroid Build Coastguard Worker }
785*795d594fSAndroid Build Coastguard Worker }
786*795d594fSAndroid Build Coastguard Worker
787*795d594fSAndroid Build Coastguard Worker jlong size = obj->SizeOf();
788*795d594fSAndroid Build Coastguard Worker
789*795d594fSAndroid Build Coastguard Worker jint length = -1;
790*795d594fSAndroid Build Coastguard Worker if (obj->IsArrayInstance()) {
791*795d594fSAndroid Build Coastguard Worker length = obj->AsArray()->GetLength();
792*795d594fSAndroid Build Coastguard Worker }
793*795d594fSAndroid Build Coastguard Worker
794*795d594fSAndroid Build Coastguard Worker jlong saved_tag = tag;
795*795d594fSAndroid Build Coastguard Worker jint ret = fn(obj, callbacks, class_tag, size, &tag, length, const_cast<void*>(user_data));
796*795d594fSAndroid Build Coastguard Worker
797*795d594fSAndroid Build Coastguard Worker if (tag != saved_tag) {
798*795d594fSAndroid Build Coastguard Worker tag_table->Set(obj, tag);
799*795d594fSAndroid Build Coastguard Worker }
800*795d594fSAndroid Build Coastguard Worker
801*795d594fSAndroid Build Coastguard Worker stop_reports = (ret & JVMTI_VISIT_ABORT) != 0;
802*795d594fSAndroid Build Coastguard Worker
803*795d594fSAndroid Build Coastguard Worker if (!stop_reports) {
804*795d594fSAndroid Build Coastguard Worker jint string_ret = ReportString(obj, env, tag_table, callbacks, user_data);
805*795d594fSAndroid Build Coastguard Worker stop_reports = (string_ret & JVMTI_VISIT_ABORT) != 0;
806*795d594fSAndroid Build Coastguard Worker }
807*795d594fSAndroid Build Coastguard Worker
808*795d594fSAndroid Build Coastguard Worker if (!stop_reports) {
809*795d594fSAndroid Build Coastguard Worker jint array_ret = ReportPrimitiveArray(obj, env, tag_table, callbacks, user_data);
810*795d594fSAndroid Build Coastguard Worker stop_reports = (array_ret & JVMTI_VISIT_ABORT) != 0;
811*795d594fSAndroid Build Coastguard Worker }
812*795d594fSAndroid Build Coastguard Worker
813*795d594fSAndroid Build Coastguard Worker if (!stop_reports) {
814*795d594fSAndroid Build Coastguard Worker stop_reports = ReportPrimitiveField::Report(obj, tag_table, callbacks, user_data);
815*795d594fSAndroid Build Coastguard Worker }
816*795d594fSAndroid Build Coastguard Worker };
817*795d594fSAndroid Build Coastguard Worker art::Runtime::Current()->GetHeap()->VisitObjects(visitor);
818*795d594fSAndroid Build Coastguard Worker
819*795d594fSAndroid Build Coastguard Worker return ERR(NONE);
820*795d594fSAndroid Build Coastguard Worker }
821*795d594fSAndroid Build Coastguard Worker
IterateThroughHeap(jvmtiEnv * env,jint heap_filter,jclass klass,const jvmtiHeapCallbacks * callbacks,const void * user_data)822*795d594fSAndroid Build Coastguard Worker jvmtiError HeapUtil::IterateThroughHeap(jvmtiEnv* env,
823*795d594fSAndroid Build Coastguard Worker jint heap_filter,
824*795d594fSAndroid Build Coastguard Worker jclass klass,
825*795d594fSAndroid Build Coastguard Worker const jvmtiHeapCallbacks* callbacks,
826*795d594fSAndroid Build Coastguard Worker const void* user_data) {
827*795d594fSAndroid Build Coastguard Worker auto JvmtiIterateHeap = []([[maybe_unused]] art::mirror::Object* obj,
828*795d594fSAndroid Build Coastguard Worker const jvmtiHeapCallbacks* cb_callbacks,
829*795d594fSAndroid Build Coastguard Worker jlong class_tag,
830*795d594fSAndroid Build Coastguard Worker jlong size,
831*795d594fSAndroid Build Coastguard Worker jlong* tag,
832*795d594fSAndroid Build Coastguard Worker jint length,
833*795d594fSAndroid Build Coastguard Worker void* cb_user_data) REQUIRES_SHARED(art::Locks::mutator_lock_) {
834*795d594fSAndroid Build Coastguard Worker return cb_callbacks->heap_iteration_callback(class_tag,
835*795d594fSAndroid Build Coastguard Worker size,
836*795d594fSAndroid Build Coastguard Worker tag,
837*795d594fSAndroid Build Coastguard Worker length,
838*795d594fSAndroid Build Coastguard Worker cb_user_data);
839*795d594fSAndroid Build Coastguard Worker };
840*795d594fSAndroid Build Coastguard Worker return DoIterateThroughHeap(JvmtiIterateHeap,
841*795d594fSAndroid Build Coastguard Worker env,
842*795d594fSAndroid Build Coastguard Worker ArtJvmTiEnv::AsArtJvmTiEnv(env)->object_tag_table.get(),
843*795d594fSAndroid Build Coastguard Worker heap_filter,
844*795d594fSAndroid Build Coastguard Worker klass,
845*795d594fSAndroid Build Coastguard Worker callbacks,
846*795d594fSAndroid Build Coastguard Worker user_data);
847*795d594fSAndroid Build Coastguard Worker }
848*795d594fSAndroid Build Coastguard Worker
849*795d594fSAndroid Build Coastguard Worker class FollowReferencesHelper final {
850*795d594fSAndroid Build Coastguard Worker public:
FollowReferencesHelper(HeapUtil * h,jvmtiEnv * jvmti_env,art::ObjPtr<art::mirror::Object> initial_object,const jvmtiHeapCallbacks * callbacks,art::ObjPtr<art::mirror::Class> class_filter,jint heap_filter,const void * user_data)851*795d594fSAndroid Build Coastguard Worker FollowReferencesHelper(HeapUtil* h,
852*795d594fSAndroid Build Coastguard Worker jvmtiEnv* jvmti_env,
853*795d594fSAndroid Build Coastguard Worker art::ObjPtr<art::mirror::Object> initial_object,
854*795d594fSAndroid Build Coastguard Worker const jvmtiHeapCallbacks* callbacks,
855*795d594fSAndroid Build Coastguard Worker art::ObjPtr<art::mirror::Class> class_filter,
856*795d594fSAndroid Build Coastguard Worker jint heap_filter,
857*795d594fSAndroid Build Coastguard Worker const void* user_data)
858*795d594fSAndroid Build Coastguard Worker : env(jvmti_env),
859*795d594fSAndroid Build Coastguard Worker tag_table_(h->GetTags()),
860*795d594fSAndroid Build Coastguard Worker initial_object_(initial_object),
861*795d594fSAndroid Build Coastguard Worker callbacks_(callbacks),
862*795d594fSAndroid Build Coastguard Worker class_filter_(class_filter),
863*795d594fSAndroid Build Coastguard Worker heap_filter_(heap_filter),
864*795d594fSAndroid Build Coastguard Worker user_data_(user_data),
865*795d594fSAndroid Build Coastguard Worker start_(0),
866*795d594fSAndroid Build Coastguard Worker stop_reports_(false) {
867*795d594fSAndroid Build Coastguard Worker }
868*795d594fSAndroid Build Coastguard Worker
Init()869*795d594fSAndroid Build Coastguard Worker void Init()
870*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(art::Locks::mutator_lock_)
871*795d594fSAndroid Build Coastguard Worker REQUIRES(!*tag_table_->GetAllowDisallowLock()) {
872*795d594fSAndroid Build Coastguard Worker if (initial_object_.IsNull()) {
873*795d594fSAndroid Build Coastguard Worker CollectAndReportRootsVisitor carrv(this, tag_table_, &worklist_, &visited_);
874*795d594fSAndroid Build Coastguard Worker
875*795d594fSAndroid Build Coastguard Worker // We need precise info (e.g., vregs).
876*795d594fSAndroid Build Coastguard Worker constexpr art::VisitRootFlags kRootFlags = static_cast<art::VisitRootFlags>(
877*795d594fSAndroid Build Coastguard Worker art::VisitRootFlags::kVisitRootFlagAllRoots | art::VisitRootFlags::kVisitRootFlagPrecise);
878*795d594fSAndroid Build Coastguard Worker art::Runtime::Current()->VisitRoots(&carrv, kRootFlags);
879*795d594fSAndroid Build Coastguard Worker
880*795d594fSAndroid Build Coastguard Worker art::Runtime::Current()->VisitImageRoots(&carrv);
881*795d594fSAndroid Build Coastguard Worker stop_reports_ = carrv.IsStopReports();
882*795d594fSAndroid Build Coastguard Worker
883*795d594fSAndroid Build Coastguard Worker if (stop_reports_) {
884*795d594fSAndroid Build Coastguard Worker worklist_.clear();
885*795d594fSAndroid Build Coastguard Worker }
886*795d594fSAndroid Build Coastguard Worker } else {
887*795d594fSAndroid Build Coastguard Worker visited_.insert(initial_object_.Ptr());
888*795d594fSAndroid Build Coastguard Worker worklist_.push_back(initial_object_.Ptr());
889*795d594fSAndroid Build Coastguard Worker }
890*795d594fSAndroid Build Coastguard Worker }
891*795d594fSAndroid Build Coastguard Worker
Work()892*795d594fSAndroid Build Coastguard Worker void Work()
893*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(art::Locks::mutator_lock_)
894*795d594fSAndroid Build Coastguard Worker REQUIRES(!*tag_table_->GetAllowDisallowLock()) {
895*795d594fSAndroid Build Coastguard Worker // Currently implemented as a BFS. To lower overhead, we don't erase elements immediately
896*795d594fSAndroid Build Coastguard Worker // from the head of the work list, instead postponing until there's a gap that's "large."
897*795d594fSAndroid Build Coastguard Worker //
898*795d594fSAndroid Build Coastguard Worker // Alternatively, we can implement a DFS and use the work list as a stack.
899*795d594fSAndroid Build Coastguard Worker while (start_ < worklist_.size()) {
900*795d594fSAndroid Build Coastguard Worker art::mirror::Object* cur_obj = worklist_[start_];
901*795d594fSAndroid Build Coastguard Worker start_++;
902*795d594fSAndroid Build Coastguard Worker
903*795d594fSAndroid Build Coastguard Worker if (start_ >= kMaxStart) {
904*795d594fSAndroid Build Coastguard Worker worklist_.erase(worklist_.begin(), worklist_.begin() + start_);
905*795d594fSAndroid Build Coastguard Worker start_ = 0;
906*795d594fSAndroid Build Coastguard Worker }
907*795d594fSAndroid Build Coastguard Worker
908*795d594fSAndroid Build Coastguard Worker VisitObject(cur_obj);
909*795d594fSAndroid Build Coastguard Worker
910*795d594fSAndroid Build Coastguard Worker if (stop_reports_) {
911*795d594fSAndroid Build Coastguard Worker break;
912*795d594fSAndroid Build Coastguard Worker }
913*795d594fSAndroid Build Coastguard Worker }
914*795d594fSAndroid Build Coastguard Worker }
915*795d594fSAndroid Build Coastguard Worker
916*795d594fSAndroid Build Coastguard Worker private:
917*795d594fSAndroid Build Coastguard Worker class CollectAndReportRootsVisitor final : public art::RootVisitor {
918*795d594fSAndroid Build Coastguard Worker public:
CollectAndReportRootsVisitor(FollowReferencesHelper * helper,ObjectTagTable * tag_table,std::vector<art::mirror::Object * > * worklist,std::unordered_set<art::mirror::Object * > * visited)919*795d594fSAndroid Build Coastguard Worker CollectAndReportRootsVisitor(FollowReferencesHelper* helper,
920*795d594fSAndroid Build Coastguard Worker ObjectTagTable* tag_table,
921*795d594fSAndroid Build Coastguard Worker std::vector<art::mirror::Object*>* worklist,
922*795d594fSAndroid Build Coastguard Worker std::unordered_set<art::mirror::Object*>* visited)
923*795d594fSAndroid Build Coastguard Worker : helper_(helper),
924*795d594fSAndroid Build Coastguard Worker tag_table_(tag_table),
925*795d594fSAndroid Build Coastguard Worker worklist_(worklist),
926*795d594fSAndroid Build Coastguard Worker visited_(visited),
927*795d594fSAndroid Build Coastguard Worker stop_reports_(false) {}
928*795d594fSAndroid Build Coastguard Worker
VisitRoots(art::mirror::Object *** roots,size_t count,const art::RootInfo & info)929*795d594fSAndroid Build Coastguard Worker void VisitRoots(art::mirror::Object*** roots, size_t count, const art::RootInfo& info)
930*795d594fSAndroid Build Coastguard Worker override
931*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(art::Locks::mutator_lock_)
932*795d594fSAndroid Build Coastguard Worker REQUIRES(!*helper_->tag_table_->GetAllowDisallowLock()) {
933*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; i != count; ++i) {
934*795d594fSAndroid Build Coastguard Worker AddRoot(*roots[i], info);
935*795d594fSAndroid Build Coastguard Worker }
936*795d594fSAndroid Build Coastguard Worker }
937*795d594fSAndroid Build Coastguard Worker
VisitRoots(art::mirror::CompressedReference<art::mirror::Object> ** roots,size_t count,const art::RootInfo & info)938*795d594fSAndroid Build Coastguard Worker void VisitRoots(art::mirror::CompressedReference<art::mirror::Object>** roots,
939*795d594fSAndroid Build Coastguard Worker size_t count,
940*795d594fSAndroid Build Coastguard Worker const art::RootInfo& info)
941*795d594fSAndroid Build Coastguard Worker override REQUIRES_SHARED(art::Locks::mutator_lock_)
942*795d594fSAndroid Build Coastguard Worker REQUIRES(!*helper_->tag_table_->GetAllowDisallowLock()) {
943*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; i != count; ++i) {
944*795d594fSAndroid Build Coastguard Worker AddRoot(roots[i]->AsMirrorPtr(), info);
945*795d594fSAndroid Build Coastguard Worker }
946*795d594fSAndroid Build Coastguard Worker }
947*795d594fSAndroid Build Coastguard Worker
IsStopReports()948*795d594fSAndroid Build Coastguard Worker bool IsStopReports() {
949*795d594fSAndroid Build Coastguard Worker return stop_reports_;
950*795d594fSAndroid Build Coastguard Worker }
951*795d594fSAndroid Build Coastguard Worker
952*795d594fSAndroid Build Coastguard Worker private:
AddRoot(art::mirror::Object * root_obj,const art::RootInfo & info)953*795d594fSAndroid Build Coastguard Worker void AddRoot(art::mirror::Object* root_obj, const art::RootInfo& info)
954*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(art::Locks::mutator_lock_)
955*795d594fSAndroid Build Coastguard Worker REQUIRES(!*tag_table_->GetAllowDisallowLock()) {
956*795d594fSAndroid Build Coastguard Worker if (stop_reports_) {
957*795d594fSAndroid Build Coastguard Worker return;
958*795d594fSAndroid Build Coastguard Worker }
959*795d594fSAndroid Build Coastguard Worker bool add_to_worklist = ReportRoot(root_obj, info);
960*795d594fSAndroid Build Coastguard Worker // We use visited_ to mark roots already so we do not need another set.
961*795d594fSAndroid Build Coastguard Worker if (visited_->find(root_obj) == visited_->end()) {
962*795d594fSAndroid Build Coastguard Worker if (add_to_worklist) {
963*795d594fSAndroid Build Coastguard Worker visited_->insert(root_obj);
964*795d594fSAndroid Build Coastguard Worker worklist_->push_back(root_obj);
965*795d594fSAndroid Build Coastguard Worker }
966*795d594fSAndroid Build Coastguard Worker }
967*795d594fSAndroid Build Coastguard Worker }
968*795d594fSAndroid Build Coastguard Worker
969*795d594fSAndroid Build Coastguard Worker // Remove NO_THREAD_SAFETY_ANALYSIS once ASSERT_CAPABILITY works correctly.
FindThread(const art::RootInfo & info)970*795d594fSAndroid Build Coastguard Worker art::Thread* FindThread(const art::RootInfo& info) NO_THREAD_SAFETY_ANALYSIS {
971*795d594fSAndroid Build Coastguard Worker art::Locks::thread_list_lock_->AssertExclusiveHeld(art::Thread::Current());
972*795d594fSAndroid Build Coastguard Worker return art::Runtime::Current()->GetThreadList()->FindThreadByThreadId(info.GetThreadId());
973*795d594fSAndroid Build Coastguard Worker }
974*795d594fSAndroid Build Coastguard Worker
GetReferenceKind(const art::RootInfo & info,jvmtiHeapReferenceInfo * ref_info)975*795d594fSAndroid Build Coastguard Worker jvmtiHeapReferenceKind GetReferenceKind(const art::RootInfo& info,
976*795d594fSAndroid Build Coastguard Worker jvmtiHeapReferenceInfo* ref_info)
977*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(art::Locks::mutator_lock_) {
978*795d594fSAndroid Build Coastguard Worker // We do not necessarily hold thread_list_lock_ here, but we may if we are called from
979*795d594fSAndroid Build Coastguard Worker // VisitThreadRoots, which can happen from JVMTI FollowReferences. If it was acquired in
980*795d594fSAndroid Build Coastguard Worker // ThreadList::VisitRoots, it's unsafe to temporarily release it. Thus we act as if we did
981*795d594fSAndroid Build Coastguard Worker // not hold the thread_list_lock_ here, and relax CHECKs appropriately. If it does happen,
982*795d594fSAndroid Build Coastguard Worker // we are in a SuspendAll situation with concurrent GC disabled, and should not need to run
983*795d594fSAndroid Build Coastguard Worker // flip functions. TODO: Find a way to clean this up.
984*795d594fSAndroid Build Coastguard Worker
985*795d594fSAndroid Build Coastguard Worker // TODO: Fill in ref_info.
986*795d594fSAndroid Build Coastguard Worker memset(ref_info, 0, sizeof(jvmtiHeapReferenceInfo));
987*795d594fSAndroid Build Coastguard Worker
988*795d594fSAndroid Build Coastguard Worker switch (info.GetType()) {
989*795d594fSAndroid Build Coastguard Worker case art::RootType::kRootJNIGlobal:
990*795d594fSAndroid Build Coastguard Worker return JVMTI_HEAP_REFERENCE_JNI_GLOBAL;
991*795d594fSAndroid Build Coastguard Worker
992*795d594fSAndroid Build Coastguard Worker case art::RootType::kRootJNILocal:
993*795d594fSAndroid Build Coastguard Worker {
994*795d594fSAndroid Build Coastguard Worker uint32_t thread_id = info.GetThreadId();
995*795d594fSAndroid Build Coastguard Worker ref_info->jni_local.thread_id = thread_id;
996*795d594fSAndroid Build Coastguard Worker
997*795d594fSAndroid Build Coastguard Worker art::Thread* thread = FindThread(info);
998*795d594fSAndroid Build Coastguard Worker if (thread != nullptr) {
999*795d594fSAndroid Build Coastguard Worker art::mirror::Object* thread_obj;
1000*795d594fSAndroid Build Coastguard Worker if (thread->IsStillStarting()) {
1001*795d594fSAndroid Build Coastguard Worker thread_obj = nullptr;
1002*795d594fSAndroid Build Coastguard Worker } else {
1003*795d594fSAndroid Build Coastguard Worker thread_obj = thread->GetPeerFromOtherThread();
1004*795d594fSAndroid Build Coastguard Worker }
1005*795d594fSAndroid Build Coastguard Worker if (thread_obj != nullptr) {
1006*795d594fSAndroid Build Coastguard Worker ref_info->jni_local.thread_tag = tag_table_->GetTagOrZero(thread_obj);
1007*795d594fSAndroid Build Coastguard Worker }
1008*795d594fSAndroid Build Coastguard Worker }
1009*795d594fSAndroid Build Coastguard Worker
1010*795d594fSAndroid Build Coastguard Worker // TODO: We don't have this info.
1011*795d594fSAndroid Build Coastguard Worker if (thread != nullptr) {
1012*795d594fSAndroid Build Coastguard Worker ref_info->jni_local.depth = 0;
1013*795d594fSAndroid Build Coastguard Worker art::ArtMethod* method = thread->GetCurrentMethod(nullptr,
1014*795d594fSAndroid Build Coastguard Worker /* check_suspended= */ true,
1015*795d594fSAndroid Build Coastguard Worker /* abort_on_error= */ false);
1016*795d594fSAndroid Build Coastguard Worker if (method != nullptr) {
1017*795d594fSAndroid Build Coastguard Worker ref_info->jni_local.method = art::jni::EncodeArtMethod(method);
1018*795d594fSAndroid Build Coastguard Worker }
1019*795d594fSAndroid Build Coastguard Worker }
1020*795d594fSAndroid Build Coastguard Worker
1021*795d594fSAndroid Build Coastguard Worker return JVMTI_HEAP_REFERENCE_JNI_LOCAL;
1022*795d594fSAndroid Build Coastguard Worker }
1023*795d594fSAndroid Build Coastguard Worker
1024*795d594fSAndroid Build Coastguard Worker case art::RootType::kRootJavaFrame:
1025*795d594fSAndroid Build Coastguard Worker {
1026*795d594fSAndroid Build Coastguard Worker uint32_t thread_id = info.GetThreadId();
1027*795d594fSAndroid Build Coastguard Worker ref_info->stack_local.thread_id = thread_id;
1028*795d594fSAndroid Build Coastguard Worker
1029*795d594fSAndroid Build Coastguard Worker art::Thread* thread = FindThread(info);
1030*795d594fSAndroid Build Coastguard Worker if (thread != nullptr) {
1031*795d594fSAndroid Build Coastguard Worker art::mirror::Object* thread_obj;
1032*795d594fSAndroid Build Coastguard Worker if (thread->IsStillStarting()) {
1033*795d594fSAndroid Build Coastguard Worker thread_obj = nullptr;
1034*795d594fSAndroid Build Coastguard Worker } else {
1035*795d594fSAndroid Build Coastguard Worker thread_obj = thread->GetPeerFromOtherThread();
1036*795d594fSAndroid Build Coastguard Worker }
1037*795d594fSAndroid Build Coastguard Worker if (thread_obj != nullptr) {
1038*795d594fSAndroid Build Coastguard Worker ref_info->stack_local.thread_tag = tag_table_->GetTagOrZero(thread_obj);
1039*795d594fSAndroid Build Coastguard Worker }
1040*795d594fSAndroid Build Coastguard Worker }
1041*795d594fSAndroid Build Coastguard Worker
1042*795d594fSAndroid Build Coastguard Worker auto& java_info = static_cast<const art::JavaFrameRootInfo&>(info);
1043*795d594fSAndroid Build Coastguard Worker size_t vreg = java_info.GetVReg();
1044*795d594fSAndroid Build Coastguard Worker ref_info->stack_local.slot = static_cast<jint>(
1045*795d594fSAndroid Build Coastguard Worker vreg <= art::JavaFrameRootInfo::kMaxVReg ? vreg : -1);
1046*795d594fSAndroid Build Coastguard Worker const art::StackVisitor* visitor = java_info.GetVisitor();
1047*795d594fSAndroid Build Coastguard Worker ref_info->stack_local.location =
1048*795d594fSAndroid Build Coastguard Worker static_cast<jlocation>(visitor->GetDexPc(/* abort_on_failure= */ false));
1049*795d594fSAndroid Build Coastguard Worker ref_info->stack_local.depth = static_cast<jint>(visitor->GetFrameDepth());
1050*795d594fSAndroid Build Coastguard Worker art::ArtMethod* method = visitor->GetMethod();
1051*795d594fSAndroid Build Coastguard Worker if (method != nullptr) {
1052*795d594fSAndroid Build Coastguard Worker ref_info->stack_local.method = art::jni::EncodeArtMethod(method);
1053*795d594fSAndroid Build Coastguard Worker }
1054*795d594fSAndroid Build Coastguard Worker
1055*795d594fSAndroid Build Coastguard Worker return JVMTI_HEAP_REFERENCE_STACK_LOCAL;
1056*795d594fSAndroid Build Coastguard Worker }
1057*795d594fSAndroid Build Coastguard Worker
1058*795d594fSAndroid Build Coastguard Worker case art::RootType::kRootNativeStack:
1059*795d594fSAndroid Build Coastguard Worker case art::RootType::kRootThreadBlock:
1060*795d594fSAndroid Build Coastguard Worker case art::RootType::kRootThreadObject:
1061*795d594fSAndroid Build Coastguard Worker return JVMTI_HEAP_REFERENCE_THREAD;
1062*795d594fSAndroid Build Coastguard Worker
1063*795d594fSAndroid Build Coastguard Worker case art::RootType::kRootStickyClass:
1064*795d594fSAndroid Build Coastguard Worker case art::RootType::kRootInternedString:
1065*795d594fSAndroid Build Coastguard Worker // Note: this isn't a root in the RI.
1066*795d594fSAndroid Build Coastguard Worker return JVMTI_HEAP_REFERENCE_SYSTEM_CLASS;
1067*795d594fSAndroid Build Coastguard Worker
1068*795d594fSAndroid Build Coastguard Worker case art::RootType::kRootMonitorUsed:
1069*795d594fSAndroid Build Coastguard Worker case art::RootType::kRootJNIMonitor:
1070*795d594fSAndroid Build Coastguard Worker return JVMTI_HEAP_REFERENCE_MONITOR;
1071*795d594fSAndroid Build Coastguard Worker
1072*795d594fSAndroid Build Coastguard Worker case art::RootType::kRootFinalizing:
1073*795d594fSAndroid Build Coastguard Worker case art::RootType::kRootDebugger:
1074*795d594fSAndroid Build Coastguard Worker case art::RootType::kRootReferenceCleanup:
1075*795d594fSAndroid Build Coastguard Worker case art::RootType::kRootVMInternal:
1076*795d594fSAndroid Build Coastguard Worker case art::RootType::kRootUnknown:
1077*795d594fSAndroid Build Coastguard Worker return JVMTI_HEAP_REFERENCE_OTHER;
1078*795d594fSAndroid Build Coastguard Worker }
1079*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unreachable";
1080*795d594fSAndroid Build Coastguard Worker UNREACHABLE();
1081*795d594fSAndroid Build Coastguard Worker }
1082*795d594fSAndroid Build Coastguard Worker
ReportRoot(art::mirror::Object * root_obj,const art::RootInfo & info)1083*795d594fSAndroid Build Coastguard Worker bool ReportRoot(art::mirror::Object* root_obj, const art::RootInfo& info)
1084*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(art::Locks::mutator_lock_)
1085*795d594fSAndroid Build Coastguard Worker REQUIRES(!*tag_table_->GetAllowDisallowLock()) {
1086*795d594fSAndroid Build Coastguard Worker jvmtiHeapReferenceInfo ref_info;
1087*795d594fSAndroid Build Coastguard Worker jvmtiHeapReferenceKind kind = GetReferenceKind(info, &ref_info);
1088*795d594fSAndroid Build Coastguard Worker jint result = helper_->ReportReference(kind, &ref_info, nullptr, root_obj);
1089*795d594fSAndroid Build Coastguard Worker if ((result & JVMTI_VISIT_ABORT) != 0) {
1090*795d594fSAndroid Build Coastguard Worker stop_reports_ = true;
1091*795d594fSAndroid Build Coastguard Worker }
1092*795d594fSAndroid Build Coastguard Worker return (result & JVMTI_VISIT_OBJECTS) != 0;
1093*795d594fSAndroid Build Coastguard Worker }
1094*795d594fSAndroid Build Coastguard Worker
1095*795d594fSAndroid Build Coastguard Worker private:
1096*795d594fSAndroid Build Coastguard Worker FollowReferencesHelper* helper_;
1097*795d594fSAndroid Build Coastguard Worker ObjectTagTable* tag_table_;
1098*795d594fSAndroid Build Coastguard Worker std::vector<art::mirror::Object*>* worklist_;
1099*795d594fSAndroid Build Coastguard Worker std::unordered_set<art::mirror::Object*>* visited_;
1100*795d594fSAndroid Build Coastguard Worker bool stop_reports_;
1101*795d594fSAndroid Build Coastguard Worker };
1102*795d594fSAndroid Build Coastguard Worker
VisitObject(art::mirror::Object * obj)1103*795d594fSAndroid Build Coastguard Worker void VisitObject(art::mirror::Object* obj)
1104*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(art::Locks::mutator_lock_)
1105*795d594fSAndroid Build Coastguard Worker REQUIRES(!*tag_table_->GetAllowDisallowLock()) {
1106*795d594fSAndroid Build Coastguard Worker if (obj->IsClass()) {
1107*795d594fSAndroid Build Coastguard Worker VisitClass(obj->AsClass().Ptr());
1108*795d594fSAndroid Build Coastguard Worker return;
1109*795d594fSAndroid Build Coastguard Worker }
1110*795d594fSAndroid Build Coastguard Worker if (obj->IsArrayInstance()) {
1111*795d594fSAndroid Build Coastguard Worker VisitArray(obj);
1112*795d594fSAndroid Build Coastguard Worker return;
1113*795d594fSAndroid Build Coastguard Worker }
1114*795d594fSAndroid Build Coastguard Worker
1115*795d594fSAndroid Build Coastguard Worker // All instance fields.
1116*795d594fSAndroid Build Coastguard Worker auto report_instance_field =
1117*795d594fSAndroid Build Coastguard Worker [&](art::ObjPtr<art::mirror::Object> src,
1118*795d594fSAndroid Build Coastguard Worker [[maybe_unused]] art::ObjPtr<art::mirror::Class> obj_klass,
1119*795d594fSAndroid Build Coastguard Worker art::ArtField& field,
1120*795d594fSAndroid Build Coastguard Worker size_t field_index,
1121*795d594fSAndroid Build Coastguard Worker [[maybe_unused]] void* user_data) REQUIRES_SHARED(art::Locks::mutator_lock_)
1122*795d594fSAndroid Build Coastguard Worker REQUIRES(!*tag_table_->GetAllowDisallowLock()) {
1123*795d594fSAndroid Build Coastguard Worker art::ObjPtr<art::mirror::Object> field_value = field.GetObject(src);
1124*795d594fSAndroid Build Coastguard Worker if (field_value != nullptr) {
1125*795d594fSAndroid Build Coastguard Worker jvmtiHeapReferenceInfo reference_info;
1126*795d594fSAndroid Build Coastguard Worker memset(&reference_info, 0, sizeof(reference_info));
1127*795d594fSAndroid Build Coastguard Worker
1128*795d594fSAndroid Build Coastguard Worker reference_info.field.index = field_index;
1129*795d594fSAndroid Build Coastguard Worker
1130*795d594fSAndroid Build Coastguard Worker jvmtiHeapReferenceKind kind =
1131*795d594fSAndroid Build Coastguard Worker field.GetOffset().Int32Value() ==
1132*795d594fSAndroid Build Coastguard Worker art::mirror::Object::ClassOffset().Int32Value() ?
1133*795d594fSAndroid Build Coastguard Worker JVMTI_HEAP_REFERENCE_CLASS :
1134*795d594fSAndroid Build Coastguard Worker JVMTI_HEAP_REFERENCE_FIELD;
1135*795d594fSAndroid Build Coastguard Worker const jvmtiHeapReferenceInfo* reference_info_ptr =
1136*795d594fSAndroid Build Coastguard Worker kind == JVMTI_HEAP_REFERENCE_CLASS ? nullptr : &reference_info;
1137*795d594fSAndroid Build Coastguard Worker
1138*795d594fSAndroid Build Coastguard Worker return !ReportReferenceMaybeEnqueue(
1139*795d594fSAndroid Build Coastguard Worker kind, reference_info_ptr, src.Ptr(), field_value.Ptr());
1140*795d594fSAndroid Build Coastguard Worker }
1141*795d594fSAndroid Build Coastguard Worker return false;
1142*795d594fSAndroid Build Coastguard Worker };
1143*795d594fSAndroid Build Coastguard Worker stop_reports_ = FieldVisitor<void, true>::ReportFields(obj,
1144*795d594fSAndroid Build Coastguard Worker nullptr,
1145*795d594fSAndroid Build Coastguard Worker VisitorFalse<void>,
1146*795d594fSAndroid Build Coastguard Worker VisitorFalse<void>,
1147*795d594fSAndroid Build Coastguard Worker VisitorFalse<void>,
1148*795d594fSAndroid Build Coastguard Worker report_instance_field);
1149*795d594fSAndroid Build Coastguard Worker if (stop_reports_) {
1150*795d594fSAndroid Build Coastguard Worker return;
1151*795d594fSAndroid Build Coastguard Worker }
1152*795d594fSAndroid Build Coastguard Worker
1153*795d594fSAndroid Build Coastguard Worker jint string_ret = ReportString(obj, env, tag_table_, callbacks_, user_data_);
1154*795d594fSAndroid Build Coastguard Worker stop_reports_ = (string_ret & JVMTI_VISIT_ABORT) != 0;
1155*795d594fSAndroid Build Coastguard Worker if (stop_reports_) {
1156*795d594fSAndroid Build Coastguard Worker return;
1157*795d594fSAndroid Build Coastguard Worker }
1158*795d594fSAndroid Build Coastguard Worker
1159*795d594fSAndroid Build Coastguard Worker stop_reports_ = ReportPrimitiveField::Report(obj, tag_table_, callbacks_, user_data_);
1160*795d594fSAndroid Build Coastguard Worker }
1161*795d594fSAndroid Build Coastguard Worker
VisitArray(art::mirror::Object * array)1162*795d594fSAndroid Build Coastguard Worker void VisitArray(art::mirror::Object* array)
1163*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(art::Locks::mutator_lock_)
1164*795d594fSAndroid Build Coastguard Worker REQUIRES(!*tag_table_->GetAllowDisallowLock()) {
1165*795d594fSAndroid Build Coastguard Worker stop_reports_ = !ReportReferenceMaybeEnqueue(JVMTI_HEAP_REFERENCE_CLASS,
1166*795d594fSAndroid Build Coastguard Worker nullptr,
1167*795d594fSAndroid Build Coastguard Worker array,
1168*795d594fSAndroid Build Coastguard Worker array->GetClass());
1169*795d594fSAndroid Build Coastguard Worker if (stop_reports_) {
1170*795d594fSAndroid Build Coastguard Worker return;
1171*795d594fSAndroid Build Coastguard Worker }
1172*795d594fSAndroid Build Coastguard Worker
1173*795d594fSAndroid Build Coastguard Worker if (array->IsObjectArray()) {
1174*795d594fSAndroid Build Coastguard Worker art::ObjPtr<art::mirror::ObjectArray<art::mirror::Object>> obj_array =
1175*795d594fSAndroid Build Coastguard Worker array->AsObjectArray<art::mirror::Object>();
1176*795d594fSAndroid Build Coastguard Worker for (auto elem_pair : art::ZipCount(obj_array->Iterate())) {
1177*795d594fSAndroid Build Coastguard Worker if (elem_pair.first != nullptr) {
1178*795d594fSAndroid Build Coastguard Worker jvmtiHeapReferenceInfo reference_info;
1179*795d594fSAndroid Build Coastguard Worker reference_info.array.index = elem_pair.second;
1180*795d594fSAndroid Build Coastguard Worker stop_reports_ = !ReportReferenceMaybeEnqueue(JVMTI_HEAP_REFERENCE_ARRAY_ELEMENT,
1181*795d594fSAndroid Build Coastguard Worker &reference_info,
1182*795d594fSAndroid Build Coastguard Worker array,
1183*795d594fSAndroid Build Coastguard Worker elem_pair.first.Ptr());
1184*795d594fSAndroid Build Coastguard Worker if (stop_reports_) {
1185*795d594fSAndroid Build Coastguard Worker break;
1186*795d594fSAndroid Build Coastguard Worker }
1187*795d594fSAndroid Build Coastguard Worker }
1188*795d594fSAndroid Build Coastguard Worker }
1189*795d594fSAndroid Build Coastguard Worker } else {
1190*795d594fSAndroid Build Coastguard Worker if (!stop_reports_) {
1191*795d594fSAndroid Build Coastguard Worker jint array_ret = ReportPrimitiveArray(array, env, tag_table_, callbacks_, user_data_);
1192*795d594fSAndroid Build Coastguard Worker stop_reports_ = (array_ret & JVMTI_VISIT_ABORT) != 0;
1193*795d594fSAndroid Build Coastguard Worker }
1194*795d594fSAndroid Build Coastguard Worker }
1195*795d594fSAndroid Build Coastguard Worker }
1196*795d594fSAndroid Build Coastguard Worker
VisitClass(art::mirror::Class * klass)1197*795d594fSAndroid Build Coastguard Worker void VisitClass(art::mirror::Class* klass)
1198*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(art::Locks::mutator_lock_)
1199*795d594fSAndroid Build Coastguard Worker REQUIRES(!*tag_table_->GetAllowDisallowLock()) {
1200*795d594fSAndroid Build Coastguard Worker // TODO: Are erroneous classes reported? Are non-prepared ones? For now, just use resolved ones.
1201*795d594fSAndroid Build Coastguard Worker if (!klass->IsResolved()) {
1202*795d594fSAndroid Build Coastguard Worker return;
1203*795d594fSAndroid Build Coastguard Worker }
1204*795d594fSAndroid Build Coastguard Worker
1205*795d594fSAndroid Build Coastguard Worker // Superclass.
1206*795d594fSAndroid Build Coastguard Worker stop_reports_ = !ReportReferenceMaybeEnqueue(JVMTI_HEAP_REFERENCE_SUPERCLASS,
1207*795d594fSAndroid Build Coastguard Worker nullptr,
1208*795d594fSAndroid Build Coastguard Worker klass,
1209*795d594fSAndroid Build Coastguard Worker klass->GetSuperClass().Ptr());
1210*795d594fSAndroid Build Coastguard Worker if (stop_reports_) {
1211*795d594fSAndroid Build Coastguard Worker return;
1212*795d594fSAndroid Build Coastguard Worker }
1213*795d594fSAndroid Build Coastguard Worker
1214*795d594fSAndroid Build Coastguard Worker // Directly implemented or extended interfaces.
1215*795d594fSAndroid Build Coastguard Worker art::Thread* self = art::Thread::Current();
1216*795d594fSAndroid Build Coastguard Worker art::StackHandleScope<1> hs(self);
1217*795d594fSAndroid Build Coastguard Worker art::Handle<art::mirror::Class> h_klass(hs.NewHandle<art::mirror::Class>(klass));
1218*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; i < h_klass->NumDirectInterfaces(); ++i) {
1219*795d594fSAndroid Build Coastguard Worker art::ObjPtr<art::mirror::Class> inf_klass =
1220*795d594fSAndroid Build Coastguard Worker art::mirror::Class::ResolveDirectInterface(self, h_klass, i);
1221*795d594fSAndroid Build Coastguard Worker if (inf_klass == nullptr) {
1222*795d594fSAndroid Build Coastguard Worker // TODO: With a resolved class this should not happen...
1223*795d594fSAndroid Build Coastguard Worker self->ClearException();
1224*795d594fSAndroid Build Coastguard Worker break;
1225*795d594fSAndroid Build Coastguard Worker }
1226*795d594fSAndroid Build Coastguard Worker
1227*795d594fSAndroid Build Coastguard Worker stop_reports_ = !ReportReferenceMaybeEnqueue(JVMTI_HEAP_REFERENCE_INTERFACE,
1228*795d594fSAndroid Build Coastguard Worker nullptr,
1229*795d594fSAndroid Build Coastguard Worker klass,
1230*795d594fSAndroid Build Coastguard Worker inf_klass.Ptr());
1231*795d594fSAndroid Build Coastguard Worker if (stop_reports_) {
1232*795d594fSAndroid Build Coastguard Worker return;
1233*795d594fSAndroid Build Coastguard Worker }
1234*795d594fSAndroid Build Coastguard Worker }
1235*795d594fSAndroid Build Coastguard Worker
1236*795d594fSAndroid Build Coastguard Worker // Classloader.
1237*795d594fSAndroid Build Coastguard Worker // TODO: What about the boot classpath loader? We'll skip for now, but do we have to find the
1238*795d594fSAndroid Build Coastguard Worker // fake BootClassLoader?
1239*795d594fSAndroid Build Coastguard Worker if (klass->GetClassLoader() != nullptr) {
1240*795d594fSAndroid Build Coastguard Worker stop_reports_ = !ReportReferenceMaybeEnqueue(JVMTI_HEAP_REFERENCE_CLASS_LOADER,
1241*795d594fSAndroid Build Coastguard Worker nullptr,
1242*795d594fSAndroid Build Coastguard Worker klass,
1243*795d594fSAndroid Build Coastguard Worker klass->GetClassLoader().Ptr());
1244*795d594fSAndroid Build Coastguard Worker if (stop_reports_) {
1245*795d594fSAndroid Build Coastguard Worker return;
1246*795d594fSAndroid Build Coastguard Worker }
1247*795d594fSAndroid Build Coastguard Worker }
1248*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(h_klass.Get(), klass);
1249*795d594fSAndroid Build Coastguard Worker
1250*795d594fSAndroid Build Coastguard Worker // Declared static fields.
1251*795d594fSAndroid Build Coastguard Worker auto report_static_field =
1252*795d594fSAndroid Build Coastguard Worker [&]([[maybe_unused]] art::ObjPtr<art::mirror::Object> obj,
1253*795d594fSAndroid Build Coastguard Worker art::ObjPtr<art::mirror::Class> obj_klass,
1254*795d594fSAndroid Build Coastguard Worker art::ArtField& field,
1255*795d594fSAndroid Build Coastguard Worker size_t field_index,
1256*795d594fSAndroid Build Coastguard Worker [[maybe_unused]] void* user_data) REQUIRES_SHARED(art::Locks::mutator_lock_)
1257*795d594fSAndroid Build Coastguard Worker REQUIRES(!*tag_table_->GetAllowDisallowLock()) {
1258*795d594fSAndroid Build Coastguard Worker art::ObjPtr<art::mirror::Object> field_value = field.GetObject(obj_klass);
1259*795d594fSAndroid Build Coastguard Worker if (field_value != nullptr) {
1260*795d594fSAndroid Build Coastguard Worker jvmtiHeapReferenceInfo reference_info;
1261*795d594fSAndroid Build Coastguard Worker memset(&reference_info, 0, sizeof(reference_info));
1262*795d594fSAndroid Build Coastguard Worker
1263*795d594fSAndroid Build Coastguard Worker reference_info.field.index = static_cast<jint>(field_index);
1264*795d594fSAndroid Build Coastguard Worker
1265*795d594fSAndroid Build Coastguard Worker return !ReportReferenceMaybeEnqueue(JVMTI_HEAP_REFERENCE_STATIC_FIELD,
1266*795d594fSAndroid Build Coastguard Worker &reference_info,
1267*795d594fSAndroid Build Coastguard Worker obj_klass.Ptr(),
1268*795d594fSAndroid Build Coastguard Worker field_value.Ptr());
1269*795d594fSAndroid Build Coastguard Worker }
1270*795d594fSAndroid Build Coastguard Worker return false;
1271*795d594fSAndroid Build Coastguard Worker };
1272*795d594fSAndroid Build Coastguard Worker stop_reports_ = FieldVisitor<void, false>::ReportFields(klass,
1273*795d594fSAndroid Build Coastguard Worker nullptr,
1274*795d594fSAndroid Build Coastguard Worker VisitorFalse<void>,
1275*795d594fSAndroid Build Coastguard Worker report_static_field,
1276*795d594fSAndroid Build Coastguard Worker VisitorFalse<void>,
1277*795d594fSAndroid Build Coastguard Worker VisitorFalse<void>);
1278*795d594fSAndroid Build Coastguard Worker if (stop_reports_) {
1279*795d594fSAndroid Build Coastguard Worker return;
1280*795d594fSAndroid Build Coastguard Worker }
1281*795d594fSAndroid Build Coastguard Worker
1282*795d594fSAndroid Build Coastguard Worker stop_reports_ = ReportPrimitiveField::Report(klass, tag_table_, callbacks_, user_data_);
1283*795d594fSAndroid Build Coastguard Worker }
1284*795d594fSAndroid Build Coastguard Worker
MaybeEnqueue(art::mirror::Object * obj)1285*795d594fSAndroid Build Coastguard Worker void MaybeEnqueue(art::mirror::Object* obj) REQUIRES_SHARED(art::Locks::mutator_lock_) {
1286*795d594fSAndroid Build Coastguard Worker if (visited_.find(obj) == visited_.end()) {
1287*795d594fSAndroid Build Coastguard Worker worklist_.push_back(obj);
1288*795d594fSAndroid Build Coastguard Worker visited_.insert(obj);
1289*795d594fSAndroid Build Coastguard Worker }
1290*795d594fSAndroid Build Coastguard Worker }
1291*795d594fSAndroid Build Coastguard Worker
ReportReferenceMaybeEnqueue(jvmtiHeapReferenceKind kind,const jvmtiHeapReferenceInfo * reference_info,art::mirror::Object * referree,art::mirror::Object * referrer)1292*795d594fSAndroid Build Coastguard Worker bool ReportReferenceMaybeEnqueue(jvmtiHeapReferenceKind kind,
1293*795d594fSAndroid Build Coastguard Worker const jvmtiHeapReferenceInfo* reference_info,
1294*795d594fSAndroid Build Coastguard Worker art::mirror::Object* referree,
1295*795d594fSAndroid Build Coastguard Worker art::mirror::Object* referrer)
1296*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(art::Locks::mutator_lock_)
1297*795d594fSAndroid Build Coastguard Worker REQUIRES(!*tag_table_->GetAllowDisallowLock()) {
1298*795d594fSAndroid Build Coastguard Worker jint result = ReportReference(kind, reference_info, referree, referrer);
1299*795d594fSAndroid Build Coastguard Worker if ((result & JVMTI_VISIT_ABORT) == 0) {
1300*795d594fSAndroid Build Coastguard Worker if ((result & JVMTI_VISIT_OBJECTS) != 0) {
1301*795d594fSAndroid Build Coastguard Worker MaybeEnqueue(referrer);
1302*795d594fSAndroid Build Coastguard Worker }
1303*795d594fSAndroid Build Coastguard Worker return true;
1304*795d594fSAndroid Build Coastguard Worker } else {
1305*795d594fSAndroid Build Coastguard Worker return false;
1306*795d594fSAndroid Build Coastguard Worker }
1307*795d594fSAndroid Build Coastguard Worker }
1308*795d594fSAndroid Build Coastguard Worker
ReportReference(jvmtiHeapReferenceKind kind,const jvmtiHeapReferenceInfo * reference_info,art::mirror::Object * referrer,art::mirror::Object * referree)1309*795d594fSAndroid Build Coastguard Worker jint ReportReference(jvmtiHeapReferenceKind kind,
1310*795d594fSAndroid Build Coastguard Worker const jvmtiHeapReferenceInfo* reference_info,
1311*795d594fSAndroid Build Coastguard Worker art::mirror::Object* referrer,
1312*795d594fSAndroid Build Coastguard Worker art::mirror::Object* referree)
1313*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(art::Locks::mutator_lock_)
1314*795d594fSAndroid Build Coastguard Worker REQUIRES(!*tag_table_->GetAllowDisallowLock()) {
1315*795d594fSAndroid Build Coastguard Worker if (referree == nullptr || stop_reports_) {
1316*795d594fSAndroid Build Coastguard Worker return 0;
1317*795d594fSAndroid Build Coastguard Worker }
1318*795d594fSAndroid Build Coastguard Worker
1319*795d594fSAndroid Build Coastguard Worker if (UNLIKELY(class_filter_ != nullptr) && class_filter_ != referree->GetClass()) {
1320*795d594fSAndroid Build Coastguard Worker return JVMTI_VISIT_OBJECTS;
1321*795d594fSAndroid Build Coastguard Worker }
1322*795d594fSAndroid Build Coastguard Worker
1323*795d594fSAndroid Build Coastguard Worker const jlong class_tag = tag_table_->GetTagOrZero(referree->GetClass());
1324*795d594fSAndroid Build Coastguard Worker jlong tag = tag_table_->GetTagOrZero(referree);
1325*795d594fSAndroid Build Coastguard Worker
1326*795d594fSAndroid Build Coastguard Worker if (!heap_filter_.ShouldReportByHeapFilter(tag, class_tag)) {
1327*795d594fSAndroid Build Coastguard Worker return JVMTI_VISIT_OBJECTS;
1328*795d594fSAndroid Build Coastguard Worker }
1329*795d594fSAndroid Build Coastguard Worker
1330*795d594fSAndroid Build Coastguard Worker const jlong referrer_class_tag =
1331*795d594fSAndroid Build Coastguard Worker referrer == nullptr ? 0 : tag_table_->GetTagOrZero(referrer->GetClass());
1332*795d594fSAndroid Build Coastguard Worker const jlong size = static_cast<jlong>(referree->SizeOf());
1333*795d594fSAndroid Build Coastguard Worker jlong saved_tag = tag;
1334*795d594fSAndroid Build Coastguard Worker jlong referrer_tag = 0;
1335*795d594fSAndroid Build Coastguard Worker jlong saved_referrer_tag = 0;
1336*795d594fSAndroid Build Coastguard Worker jlong* referrer_tag_ptr;
1337*795d594fSAndroid Build Coastguard Worker if (referrer == nullptr) {
1338*795d594fSAndroid Build Coastguard Worker referrer_tag_ptr = nullptr;
1339*795d594fSAndroid Build Coastguard Worker } else {
1340*795d594fSAndroid Build Coastguard Worker if (referrer == referree) {
1341*795d594fSAndroid Build Coastguard Worker referrer_tag_ptr = &tag;
1342*795d594fSAndroid Build Coastguard Worker } else {
1343*795d594fSAndroid Build Coastguard Worker referrer_tag = saved_referrer_tag = tag_table_->GetTagOrZero(referrer);
1344*795d594fSAndroid Build Coastguard Worker referrer_tag_ptr = &referrer_tag;
1345*795d594fSAndroid Build Coastguard Worker }
1346*795d594fSAndroid Build Coastguard Worker }
1347*795d594fSAndroid Build Coastguard Worker
1348*795d594fSAndroid Build Coastguard Worker jint length = -1;
1349*795d594fSAndroid Build Coastguard Worker if (referree->IsArrayInstance()) {
1350*795d594fSAndroid Build Coastguard Worker length = referree->AsArray()->GetLength();
1351*795d594fSAndroid Build Coastguard Worker }
1352*795d594fSAndroid Build Coastguard Worker
1353*795d594fSAndroid Build Coastguard Worker jint result = callbacks_->heap_reference_callback(kind,
1354*795d594fSAndroid Build Coastguard Worker reference_info,
1355*795d594fSAndroid Build Coastguard Worker class_tag,
1356*795d594fSAndroid Build Coastguard Worker referrer_class_tag,
1357*795d594fSAndroid Build Coastguard Worker size,
1358*795d594fSAndroid Build Coastguard Worker &tag,
1359*795d594fSAndroid Build Coastguard Worker referrer_tag_ptr,
1360*795d594fSAndroid Build Coastguard Worker length,
1361*795d594fSAndroid Build Coastguard Worker const_cast<void*>(user_data_));
1362*795d594fSAndroid Build Coastguard Worker
1363*795d594fSAndroid Build Coastguard Worker if (tag != saved_tag) {
1364*795d594fSAndroid Build Coastguard Worker tag_table_->Set(referree, tag);
1365*795d594fSAndroid Build Coastguard Worker }
1366*795d594fSAndroid Build Coastguard Worker if (referrer_tag != saved_referrer_tag) {
1367*795d594fSAndroid Build Coastguard Worker tag_table_->Set(referrer, referrer_tag);
1368*795d594fSAndroid Build Coastguard Worker }
1369*795d594fSAndroid Build Coastguard Worker
1370*795d594fSAndroid Build Coastguard Worker return result;
1371*795d594fSAndroid Build Coastguard Worker }
1372*795d594fSAndroid Build Coastguard Worker
1373*795d594fSAndroid Build Coastguard Worker jvmtiEnv* env;
1374*795d594fSAndroid Build Coastguard Worker ObjectTagTable* tag_table_;
1375*795d594fSAndroid Build Coastguard Worker art::ObjPtr<art::mirror::Object> initial_object_;
1376*795d594fSAndroid Build Coastguard Worker const jvmtiHeapCallbacks* callbacks_;
1377*795d594fSAndroid Build Coastguard Worker art::ObjPtr<art::mirror::Class> class_filter_;
1378*795d594fSAndroid Build Coastguard Worker const HeapFilter heap_filter_;
1379*795d594fSAndroid Build Coastguard Worker const void* user_data_;
1380*795d594fSAndroid Build Coastguard Worker
1381*795d594fSAndroid Build Coastguard Worker std::vector<art::mirror::Object*> worklist_;
1382*795d594fSAndroid Build Coastguard Worker size_t start_;
1383*795d594fSAndroid Build Coastguard Worker static constexpr size_t kMaxStart = 1000000U;
1384*795d594fSAndroid Build Coastguard Worker
1385*795d594fSAndroid Build Coastguard Worker std::unordered_set<art::mirror::Object*> visited_;
1386*795d594fSAndroid Build Coastguard Worker
1387*795d594fSAndroid Build Coastguard Worker bool stop_reports_;
1388*795d594fSAndroid Build Coastguard Worker
1389*795d594fSAndroid Build Coastguard Worker friend class CollectAndReportRootsVisitor;
1390*795d594fSAndroid Build Coastguard Worker };
1391*795d594fSAndroid Build Coastguard Worker
FollowReferences(jvmtiEnv * env,jint heap_filter,jclass klass,jobject initial_object,const jvmtiHeapCallbacks * callbacks,const void * user_data)1392*795d594fSAndroid Build Coastguard Worker jvmtiError HeapUtil::FollowReferences(jvmtiEnv* env,
1393*795d594fSAndroid Build Coastguard Worker jint heap_filter,
1394*795d594fSAndroid Build Coastguard Worker jclass klass,
1395*795d594fSAndroid Build Coastguard Worker jobject initial_object,
1396*795d594fSAndroid Build Coastguard Worker const jvmtiHeapCallbacks* callbacks,
1397*795d594fSAndroid Build Coastguard Worker const void* user_data) {
1398*795d594fSAndroid Build Coastguard Worker if (callbacks == nullptr) {
1399*795d594fSAndroid Build Coastguard Worker return ERR(NULL_POINTER);
1400*795d594fSAndroid Build Coastguard Worker }
1401*795d594fSAndroid Build Coastguard Worker
1402*795d594fSAndroid Build Coastguard Worker art::Thread* self = art::Thread::Current();
1403*795d594fSAndroid Build Coastguard Worker
1404*795d594fSAndroid Build Coastguard Worker art::gc::Heap* heap = art::Runtime::Current()->GetHeap();
1405*795d594fSAndroid Build Coastguard Worker if (heap->IsGcConcurrentAndMoving()) {
1406*795d594fSAndroid Build Coastguard Worker // Need to take a heap dump while GC isn't running. See the
1407*795d594fSAndroid Build Coastguard Worker // comment in Heap::VisitObjects().
1408*795d594fSAndroid Build Coastguard Worker heap->IncrementDisableMovingGC(self);
1409*795d594fSAndroid Build Coastguard Worker }
1410*795d594fSAndroid Build Coastguard Worker {
1411*795d594fSAndroid Build Coastguard Worker art::ScopedObjectAccess soa(self); // Now we know we have the shared lock.
1412*795d594fSAndroid Build Coastguard Worker art::jni::ScopedEnableSuspendAllJniIdQueries sjni; // make sure we can get JNI ids.
1413*795d594fSAndroid Build Coastguard Worker art::ScopedThreadSuspension sts(self, art::ThreadState::kWaitingForVisitObjects);
1414*795d594fSAndroid Build Coastguard Worker art::ScopedSuspendAll ssa("FollowReferences");
1415*795d594fSAndroid Build Coastguard Worker
1416*795d594fSAndroid Build Coastguard Worker art::ObjPtr<art::mirror::Class> class_filter = klass == nullptr
1417*795d594fSAndroid Build Coastguard Worker ? nullptr
1418*795d594fSAndroid Build Coastguard Worker : art::ObjPtr<art::mirror::Class>::DownCast(self->DecodeJObject(klass));
1419*795d594fSAndroid Build Coastguard Worker FollowReferencesHelper frh(this,
1420*795d594fSAndroid Build Coastguard Worker env,
1421*795d594fSAndroid Build Coastguard Worker self->DecodeJObject(initial_object),
1422*795d594fSAndroid Build Coastguard Worker callbacks,
1423*795d594fSAndroid Build Coastguard Worker class_filter,
1424*795d594fSAndroid Build Coastguard Worker heap_filter,
1425*795d594fSAndroid Build Coastguard Worker user_data);
1426*795d594fSAndroid Build Coastguard Worker frh.Init();
1427*795d594fSAndroid Build Coastguard Worker frh.Work();
1428*795d594fSAndroid Build Coastguard Worker }
1429*795d594fSAndroid Build Coastguard Worker if (heap->IsGcConcurrentAndMoving()) {
1430*795d594fSAndroid Build Coastguard Worker heap->DecrementDisableMovingGC(self);
1431*795d594fSAndroid Build Coastguard Worker }
1432*795d594fSAndroid Build Coastguard Worker
1433*795d594fSAndroid Build Coastguard Worker return ERR(NONE);
1434*795d594fSAndroid Build Coastguard Worker }
1435*795d594fSAndroid Build Coastguard Worker
GetLoadedClasses(jvmtiEnv * env,jint * class_count_ptr,jclass ** classes_ptr)1436*795d594fSAndroid Build Coastguard Worker jvmtiError HeapUtil::GetLoadedClasses(jvmtiEnv* env,
1437*795d594fSAndroid Build Coastguard Worker jint* class_count_ptr,
1438*795d594fSAndroid Build Coastguard Worker jclass** classes_ptr) {
1439*795d594fSAndroid Build Coastguard Worker if (class_count_ptr == nullptr || classes_ptr == nullptr) {
1440*795d594fSAndroid Build Coastguard Worker return ERR(NULL_POINTER);
1441*795d594fSAndroid Build Coastguard Worker }
1442*795d594fSAndroid Build Coastguard Worker
1443*795d594fSAndroid Build Coastguard Worker class ReportClassVisitor : public art::ClassVisitor {
1444*795d594fSAndroid Build Coastguard Worker public:
1445*795d594fSAndroid Build Coastguard Worker explicit ReportClassVisitor(art::Thread* self) : self_(self) {}
1446*795d594fSAndroid Build Coastguard Worker
1447*795d594fSAndroid Build Coastguard Worker bool operator()(art::ObjPtr<art::mirror::Class> klass)
1448*795d594fSAndroid Build Coastguard Worker override REQUIRES_SHARED(art::Locks::mutator_lock_) {
1449*795d594fSAndroid Build Coastguard Worker if (klass->IsLoaded() || klass->IsErroneous()) {
1450*795d594fSAndroid Build Coastguard Worker classes_.push_back(self_->GetJniEnv()->AddLocalReference<jclass>(klass));
1451*795d594fSAndroid Build Coastguard Worker }
1452*795d594fSAndroid Build Coastguard Worker return true;
1453*795d594fSAndroid Build Coastguard Worker }
1454*795d594fSAndroid Build Coastguard Worker
1455*795d594fSAndroid Build Coastguard Worker art::Thread* self_;
1456*795d594fSAndroid Build Coastguard Worker std::vector<jclass> classes_;
1457*795d594fSAndroid Build Coastguard Worker };
1458*795d594fSAndroid Build Coastguard Worker
1459*795d594fSAndroid Build Coastguard Worker art::Thread* self = art::Thread::Current();
1460*795d594fSAndroid Build Coastguard Worker ReportClassVisitor rcv(self);
1461*795d594fSAndroid Build Coastguard Worker {
1462*795d594fSAndroid Build Coastguard Worker art::ScopedObjectAccess soa(self);
1463*795d594fSAndroid Build Coastguard Worker art::Runtime::Current()->GetClassLinker()->VisitClasses(&rcv);
1464*795d594fSAndroid Build Coastguard Worker }
1465*795d594fSAndroid Build Coastguard Worker
1466*795d594fSAndroid Build Coastguard Worker size_t size = rcv.classes_.size();
1467*795d594fSAndroid Build Coastguard Worker jclass* classes = nullptr;
1468*795d594fSAndroid Build Coastguard Worker jvmtiError alloc_ret = env->Allocate(static_cast<jlong>(size * sizeof(jclass)),
1469*795d594fSAndroid Build Coastguard Worker reinterpret_cast<unsigned char**>(&classes));
1470*795d594fSAndroid Build Coastguard Worker if (alloc_ret != ERR(NONE)) {
1471*795d594fSAndroid Build Coastguard Worker return alloc_ret;
1472*795d594fSAndroid Build Coastguard Worker }
1473*795d594fSAndroid Build Coastguard Worker
1474*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; i < size; ++i) {
1475*795d594fSAndroid Build Coastguard Worker classes[i] = rcv.classes_[i];
1476*795d594fSAndroid Build Coastguard Worker }
1477*795d594fSAndroid Build Coastguard Worker *classes_ptr = classes;
1478*795d594fSAndroid Build Coastguard Worker *class_count_ptr = static_cast<jint>(size);
1479*795d594fSAndroid Build Coastguard Worker
1480*795d594fSAndroid Build Coastguard Worker return ERR(NONE);
1481*795d594fSAndroid Build Coastguard Worker }
1482*795d594fSAndroid Build Coastguard Worker
ForceGarbageCollection(jvmtiEnv * env)1483*795d594fSAndroid Build Coastguard Worker jvmtiError HeapUtil::ForceGarbageCollection([[maybe_unused]] jvmtiEnv* env) {
1484*795d594fSAndroid Build Coastguard Worker art::Runtime::Current()->GetHeap()->CollectGarbage(/* clear_soft_references= */ false);
1485*795d594fSAndroid Build Coastguard Worker
1486*795d594fSAndroid Build Coastguard Worker return ERR(NONE);
1487*795d594fSAndroid Build Coastguard Worker }
1488*795d594fSAndroid Build Coastguard Worker
1489*795d594fSAndroid Build Coastguard Worker static constexpr jint kHeapIdDefault = 0;
1490*795d594fSAndroid Build Coastguard Worker static constexpr jint kHeapIdImage = 1;
1491*795d594fSAndroid Build Coastguard Worker static constexpr jint kHeapIdZygote = 2;
1492*795d594fSAndroid Build Coastguard Worker static constexpr jint kHeapIdApp = 3;
1493*795d594fSAndroid Build Coastguard Worker
GetHeapId(art::ObjPtr<art::mirror::Object> obj)1494*795d594fSAndroid Build Coastguard Worker static jint GetHeapId(art::ObjPtr<art::mirror::Object> obj)
1495*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(art::Locks::mutator_lock_) {
1496*795d594fSAndroid Build Coastguard Worker if (obj == nullptr) {
1497*795d594fSAndroid Build Coastguard Worker return -1;
1498*795d594fSAndroid Build Coastguard Worker }
1499*795d594fSAndroid Build Coastguard Worker
1500*795d594fSAndroid Build Coastguard Worker art::gc::Heap* const heap = art::Runtime::Current()->GetHeap();
1501*795d594fSAndroid Build Coastguard Worker const art::gc::space::ContinuousSpace* const space =
1502*795d594fSAndroid Build Coastguard Worker heap->FindContinuousSpaceFromObject(obj, true);
1503*795d594fSAndroid Build Coastguard Worker jint heap_type = kHeapIdApp;
1504*795d594fSAndroid Build Coastguard Worker if (space != nullptr) {
1505*795d594fSAndroid Build Coastguard Worker if (space->IsZygoteSpace()) {
1506*795d594fSAndroid Build Coastguard Worker heap_type = kHeapIdZygote;
1507*795d594fSAndroid Build Coastguard Worker } else if (space->IsImageSpace() && heap->ObjectIsInBootImageSpace(obj)) {
1508*795d594fSAndroid Build Coastguard Worker // Only count objects in the boot image as HPROF_HEAP_IMAGE, this leaves app image objects
1509*795d594fSAndroid Build Coastguard Worker // as HPROF_HEAP_APP. b/35762934
1510*795d594fSAndroid Build Coastguard Worker heap_type = kHeapIdImage;
1511*795d594fSAndroid Build Coastguard Worker }
1512*795d594fSAndroid Build Coastguard Worker } else {
1513*795d594fSAndroid Build Coastguard Worker const auto* los = heap->GetLargeObjectsSpace();
1514*795d594fSAndroid Build Coastguard Worker if (los->Contains(obj.Ptr()) && los->IsZygoteLargeObject(art::Thread::Current(), obj.Ptr())) {
1515*795d594fSAndroid Build Coastguard Worker heap_type = kHeapIdZygote;
1516*795d594fSAndroid Build Coastguard Worker }
1517*795d594fSAndroid Build Coastguard Worker }
1518*795d594fSAndroid Build Coastguard Worker return heap_type;
1519*795d594fSAndroid Build Coastguard Worker };
1520*795d594fSAndroid Build Coastguard Worker
GetObjectHeapId(jvmtiEnv * env,jlong tag,jint * heap_id,...)1521*795d594fSAndroid Build Coastguard Worker jvmtiError HeapExtensions::GetObjectHeapId(jvmtiEnv* env, jlong tag, jint* heap_id, ...) {
1522*795d594fSAndroid Build Coastguard Worker if (heap_id == nullptr) {
1523*795d594fSAndroid Build Coastguard Worker return ERR(NULL_POINTER);
1524*795d594fSAndroid Build Coastguard Worker }
1525*795d594fSAndroid Build Coastguard Worker
1526*795d594fSAndroid Build Coastguard Worker art::Thread* self = art::Thread::Current();
1527*795d594fSAndroid Build Coastguard Worker
1528*795d594fSAndroid Build Coastguard Worker auto work = [&]() REQUIRES_SHARED(art::Locks::mutator_lock_) {
1529*795d594fSAndroid Build Coastguard Worker ObjectTagTable* tag_table = ArtJvmTiEnv::AsArtJvmTiEnv(env)->object_tag_table.get();
1530*795d594fSAndroid Build Coastguard Worker art::ObjPtr<art::mirror::Object> obj = tag_table->Find(tag);
1531*795d594fSAndroid Build Coastguard Worker jint heap_type = GetHeapId(obj);
1532*795d594fSAndroid Build Coastguard Worker if (heap_type == -1) {
1533*795d594fSAndroid Build Coastguard Worker return ERR(NOT_FOUND);
1534*795d594fSAndroid Build Coastguard Worker }
1535*795d594fSAndroid Build Coastguard Worker *heap_id = heap_type;
1536*795d594fSAndroid Build Coastguard Worker return ERR(NONE);
1537*795d594fSAndroid Build Coastguard Worker };
1538*795d594fSAndroid Build Coastguard Worker
1539*795d594fSAndroid Build Coastguard Worker if (!art::Locks::mutator_lock_->IsSharedHeld(self)) {
1540*795d594fSAndroid Build Coastguard Worker if (!self->IsThreadSuspensionAllowable()) {
1541*795d594fSAndroid Build Coastguard Worker return ERR(INTERNAL);
1542*795d594fSAndroid Build Coastguard Worker }
1543*795d594fSAndroid Build Coastguard Worker art::ScopedObjectAccess soa(self);
1544*795d594fSAndroid Build Coastguard Worker return work();
1545*795d594fSAndroid Build Coastguard Worker } else {
1546*795d594fSAndroid Build Coastguard Worker // We cannot use SOA in this case. We might be holding the lock, but may not be in the
1547*795d594fSAndroid Build Coastguard Worker // runnable state (e.g., during GC).
1548*795d594fSAndroid Build Coastguard Worker art::Locks::mutator_lock_->AssertSharedHeld(self);
1549*795d594fSAndroid Build Coastguard Worker // TODO: Investigate why ASSERT_SHARED_CAPABILITY doesn't work.
1550*795d594fSAndroid Build Coastguard Worker auto annotalysis_workaround = [&]() NO_THREAD_SAFETY_ANALYSIS {
1551*795d594fSAndroid Build Coastguard Worker return work();
1552*795d594fSAndroid Build Coastguard Worker };
1553*795d594fSAndroid Build Coastguard Worker return annotalysis_workaround();
1554*795d594fSAndroid Build Coastguard Worker }
1555*795d594fSAndroid Build Coastguard Worker }
1556*795d594fSAndroid Build Coastguard Worker
CopyStringAndReturn(jvmtiEnv * env,const char * in,char ** out)1557*795d594fSAndroid Build Coastguard Worker static jvmtiError CopyStringAndReturn(jvmtiEnv* env, const char* in, char** out) {
1558*795d594fSAndroid Build Coastguard Worker jvmtiError error;
1559*795d594fSAndroid Build Coastguard Worker JvmtiUniquePtr<char[]> param_name = CopyString(env, in, &error);
1560*795d594fSAndroid Build Coastguard Worker if (param_name == nullptr) {
1561*795d594fSAndroid Build Coastguard Worker return error;
1562*795d594fSAndroid Build Coastguard Worker }
1563*795d594fSAndroid Build Coastguard Worker *out = param_name.release();
1564*795d594fSAndroid Build Coastguard Worker return ERR(NONE);
1565*795d594fSAndroid Build Coastguard Worker }
1566*795d594fSAndroid Build Coastguard Worker
1567*795d594fSAndroid Build Coastguard Worker static constexpr const char* kHeapIdDefaultName = "default";
1568*795d594fSAndroid Build Coastguard Worker static constexpr const char* kHeapIdImageName = "image";
1569*795d594fSAndroid Build Coastguard Worker static constexpr const char* kHeapIdZygoteName = "zygote";
1570*795d594fSAndroid Build Coastguard Worker static constexpr const char* kHeapIdAppName = "app";
1571*795d594fSAndroid Build Coastguard Worker
GetHeapName(jvmtiEnv * env,jint heap_id,char ** heap_name,...)1572*795d594fSAndroid Build Coastguard Worker jvmtiError HeapExtensions::GetHeapName(jvmtiEnv* env, jint heap_id, char** heap_name, ...) {
1573*795d594fSAndroid Build Coastguard Worker switch (heap_id) {
1574*795d594fSAndroid Build Coastguard Worker case kHeapIdDefault:
1575*795d594fSAndroid Build Coastguard Worker return CopyStringAndReturn(env, kHeapIdDefaultName, heap_name);
1576*795d594fSAndroid Build Coastguard Worker case kHeapIdImage:
1577*795d594fSAndroid Build Coastguard Worker return CopyStringAndReturn(env, kHeapIdImageName, heap_name);
1578*795d594fSAndroid Build Coastguard Worker case kHeapIdZygote:
1579*795d594fSAndroid Build Coastguard Worker return CopyStringAndReturn(env, kHeapIdZygoteName, heap_name);
1580*795d594fSAndroid Build Coastguard Worker case kHeapIdApp:
1581*795d594fSAndroid Build Coastguard Worker return CopyStringAndReturn(env, kHeapIdAppName, heap_name);
1582*795d594fSAndroid Build Coastguard Worker
1583*795d594fSAndroid Build Coastguard Worker default:
1584*795d594fSAndroid Build Coastguard Worker return ERR(ILLEGAL_ARGUMENT);
1585*795d594fSAndroid Build Coastguard Worker }
1586*795d594fSAndroid Build Coastguard Worker }
1587*795d594fSAndroid Build Coastguard Worker
IterateThroughHeapExt(jvmtiEnv * env,jint heap_filter,jclass klass,const jvmtiHeapCallbacks * callbacks,const void * user_data)1588*795d594fSAndroid Build Coastguard Worker jvmtiError HeapExtensions::IterateThroughHeapExt(jvmtiEnv* env,
1589*795d594fSAndroid Build Coastguard Worker jint heap_filter,
1590*795d594fSAndroid Build Coastguard Worker jclass klass,
1591*795d594fSAndroid Build Coastguard Worker const jvmtiHeapCallbacks* callbacks,
1592*795d594fSAndroid Build Coastguard Worker const void* user_data) {
1593*795d594fSAndroid Build Coastguard Worker if (ArtJvmTiEnv::AsArtJvmTiEnv(env)->capabilities.can_tag_objects != 1) { \
1594*795d594fSAndroid Build Coastguard Worker return ERR(MUST_POSSESS_CAPABILITY); \
1595*795d594fSAndroid Build Coastguard Worker }
1596*795d594fSAndroid Build Coastguard Worker
1597*795d594fSAndroid Build Coastguard Worker // ART extension API: Also pass the heap id.
1598*795d594fSAndroid Build Coastguard Worker auto ArtIterateHeap = [](art::mirror::Object* obj,
1599*795d594fSAndroid Build Coastguard Worker const jvmtiHeapCallbacks* cb_callbacks,
1600*795d594fSAndroid Build Coastguard Worker jlong class_tag,
1601*795d594fSAndroid Build Coastguard Worker jlong size,
1602*795d594fSAndroid Build Coastguard Worker jlong* tag,
1603*795d594fSAndroid Build Coastguard Worker jint length,
1604*795d594fSAndroid Build Coastguard Worker void* cb_user_data)
1605*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(art::Locks::mutator_lock_) {
1606*795d594fSAndroid Build Coastguard Worker jint heap_id = GetHeapId(obj);
1607*795d594fSAndroid Build Coastguard Worker using ArtExtensionAPI = jint (*)(jlong, jlong, jlong*, jint length, void*, jint);
1608*795d594fSAndroid Build Coastguard Worker return reinterpret_cast<ArtExtensionAPI>(cb_callbacks->heap_iteration_callback)(
1609*795d594fSAndroid Build Coastguard Worker class_tag, size, tag, length, cb_user_data, heap_id);
1610*795d594fSAndroid Build Coastguard Worker };
1611*795d594fSAndroid Build Coastguard Worker return DoIterateThroughHeap(ArtIterateHeap,
1612*795d594fSAndroid Build Coastguard Worker env,
1613*795d594fSAndroid Build Coastguard Worker ArtJvmTiEnv::AsArtJvmTiEnv(env)->object_tag_table.get(),
1614*795d594fSAndroid Build Coastguard Worker heap_filter,
1615*795d594fSAndroid Build Coastguard Worker klass,
1616*795d594fSAndroid Build Coastguard Worker callbacks,
1617*795d594fSAndroid Build Coastguard Worker user_data);
1618*795d594fSAndroid Build Coastguard Worker }
1619*795d594fSAndroid Build Coastguard Worker
1620*795d594fSAndroid Build Coastguard Worker namespace {
1621*795d594fSAndroid Build Coastguard Worker
1622*795d594fSAndroid Build Coastguard Worker using ObjectPtr = art::ObjPtr<art::mirror::Object>;
1623*795d594fSAndroid Build Coastguard Worker using ObjectMap = std::unordered_map<ObjectPtr, ObjectPtr, art::HashObjPtr>;
1624*795d594fSAndroid Build Coastguard Worker
ReplaceObjectReferences(const ObjectMap & map)1625*795d594fSAndroid Build Coastguard Worker static void ReplaceObjectReferences(const ObjectMap& map)
1626*795d594fSAndroid Build Coastguard Worker REQUIRES(art::Locks::mutator_lock_,
1627*795d594fSAndroid Build Coastguard Worker art::Roles::uninterruptible_) {
1628*795d594fSAndroid Build Coastguard Worker art::Runtime::Current()->GetHeap()->VisitObjectsPaused(
1629*795d594fSAndroid Build Coastguard Worker [&](art::mirror::Object* ref) REQUIRES_SHARED(art::Locks::mutator_lock_) {
1630*795d594fSAndroid Build Coastguard Worker // Rewrite all references in the object if needed.
1631*795d594fSAndroid Build Coastguard Worker class ResizeReferenceVisitor {
1632*795d594fSAndroid Build Coastguard Worker public:
1633*795d594fSAndroid Build Coastguard Worker using CompressedObj = art::mirror::CompressedReference<art::mirror::Object>;
1634*795d594fSAndroid Build Coastguard Worker explicit ResizeReferenceVisitor(const ObjectMap& map, ObjectPtr ref)
1635*795d594fSAndroid Build Coastguard Worker : map_(map), ref_(ref) {}
1636*795d594fSAndroid Build Coastguard Worker
1637*795d594fSAndroid Build Coastguard Worker // Ignore class roots.
1638*795d594fSAndroid Build Coastguard Worker void VisitRootIfNonNull(CompressedObj* root) const
1639*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(art::Locks::mutator_lock_) {
1640*795d594fSAndroid Build Coastguard Worker if (root != nullptr) {
1641*795d594fSAndroid Build Coastguard Worker VisitRoot(root);
1642*795d594fSAndroid Build Coastguard Worker }
1643*795d594fSAndroid Build Coastguard Worker }
1644*795d594fSAndroid Build Coastguard Worker void VisitRoot(CompressedObj* root) const REQUIRES_SHARED(art::Locks::mutator_lock_) {
1645*795d594fSAndroid Build Coastguard Worker auto it = map_.find(root->AsMirrorPtr());
1646*795d594fSAndroid Build Coastguard Worker if (it != map_.end()) {
1647*795d594fSAndroid Build Coastguard Worker root->Assign(it->second);
1648*795d594fSAndroid Build Coastguard Worker art::WriteBarrier::ForEveryFieldWrite(ref_);
1649*795d594fSAndroid Build Coastguard Worker }
1650*795d594fSAndroid Build Coastguard Worker }
1651*795d594fSAndroid Build Coastguard Worker
1652*795d594fSAndroid Build Coastguard Worker void operator()(art::ObjPtr<art::mirror::Object> obj,
1653*795d594fSAndroid Build Coastguard Worker art::MemberOffset off,
1654*795d594fSAndroid Build Coastguard Worker bool is_static) const
1655*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(art::Locks::mutator_lock_) {
1656*795d594fSAndroid Build Coastguard Worker auto it = map_.find(obj->GetFieldObject<art::mirror::Object>(off));
1657*795d594fSAndroid Build Coastguard Worker if (it != map_.end()) {
1658*795d594fSAndroid Build Coastguard Worker UNUSED(is_static);
1659*795d594fSAndroid Build Coastguard Worker if (UNLIKELY(!is_static && off == art::mirror::Object::ClassOffset())) {
1660*795d594fSAndroid Build Coastguard Worker // We don't want to update the declaring class of any objects. They will be replaced
1661*795d594fSAndroid Build Coastguard Worker // in the heap and we need the declaring class to know its size.
1662*795d594fSAndroid Build Coastguard Worker return;
1663*795d594fSAndroid Build Coastguard Worker } else if (UNLIKELY(!is_static && off == art::mirror::Class::SuperClassOffset() &&
1664*795d594fSAndroid Build Coastguard Worker obj->IsClass())) {
1665*795d594fSAndroid Build Coastguard Worker // We don't want to be messing with the class hierarcy either.
1666*795d594fSAndroid Build Coastguard Worker return;
1667*795d594fSAndroid Build Coastguard Worker }
1668*795d594fSAndroid Build Coastguard Worker VLOG(plugin) << "Updating field at offset " << off.Uint32Value() << " of type "
1669*795d594fSAndroid Build Coastguard Worker << obj->GetClass()->PrettyClass();
1670*795d594fSAndroid Build Coastguard Worker obj->SetFieldObject</*transaction*/ false>(off, it->second);
1671*795d594fSAndroid Build Coastguard Worker art::WriteBarrier::ForEveryFieldWrite(obj);
1672*795d594fSAndroid Build Coastguard Worker }
1673*795d594fSAndroid Build Coastguard Worker }
1674*795d594fSAndroid Build Coastguard Worker
1675*795d594fSAndroid Build Coastguard Worker // java.lang.ref.Reference visitor.
1676*795d594fSAndroid Build Coastguard Worker void operator()([[maybe_unused]] art::ObjPtr<art::mirror::Class> klass,
1677*795d594fSAndroid Build Coastguard Worker art::ObjPtr<art::mirror::Reference> ref) const
1678*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(art::Locks::mutator_lock_) {
1679*795d594fSAndroid Build Coastguard Worker operator()(ref, art::mirror::Reference::ReferentOffset(), /* is_static */ false);
1680*795d594fSAndroid Build Coastguard Worker }
1681*795d594fSAndroid Build Coastguard Worker
1682*795d594fSAndroid Build Coastguard Worker private:
1683*795d594fSAndroid Build Coastguard Worker const ObjectMap& map_;
1684*795d594fSAndroid Build Coastguard Worker ObjectPtr ref_;
1685*795d594fSAndroid Build Coastguard Worker };
1686*795d594fSAndroid Build Coastguard Worker
1687*795d594fSAndroid Build Coastguard Worker ResizeReferenceVisitor rrv(map, ref);
1688*795d594fSAndroid Build Coastguard Worker if (ref->IsClass()) {
1689*795d594fSAndroid Build Coastguard Worker // Class object native roots are the ArtField and ArtMethod 'declaring_class_' fields
1690*795d594fSAndroid Build Coastguard Worker // which we don't want to be messing with as it would break ref-visitor assumptions about
1691*795d594fSAndroid Build Coastguard Worker // what a class looks like. We want to keep the default behavior in other cases (such as
1692*795d594fSAndroid Build Coastguard Worker // dex-cache) though. Unfortunately there is no way to tell from the visitor where exactly
1693*795d594fSAndroid Build Coastguard Worker // the root came from.
1694*795d594fSAndroid Build Coastguard Worker // TODO It might be nice to have the visitors told where the reference came from.
1695*795d594fSAndroid Build Coastguard Worker ref->VisitReferences</*kVisitNativeRoots*/false>(rrv, rrv);
1696*795d594fSAndroid Build Coastguard Worker } else {
1697*795d594fSAndroid Build Coastguard Worker ref->VisitReferences</*kVisitNativeRoots*/true>(rrv, rrv);
1698*795d594fSAndroid Build Coastguard Worker }
1699*795d594fSAndroid Build Coastguard Worker });
1700*795d594fSAndroid Build Coastguard Worker }
1701*795d594fSAndroid Build Coastguard Worker
ReplaceStrongRoots(art::Thread * self,const ObjectMap & map)1702*795d594fSAndroid Build Coastguard Worker static void ReplaceStrongRoots(art::Thread* self, const ObjectMap& map)
1703*795d594fSAndroid Build Coastguard Worker REQUIRES(art::Locks::mutator_lock_, art::Roles::uninterruptible_) {
1704*795d594fSAndroid Build Coastguard Worker // replace root references expcept java frames.
1705*795d594fSAndroid Build Coastguard Worker struct ResizeRootVisitor : public art::RootVisitor {
1706*795d594fSAndroid Build Coastguard Worker public:
1707*795d594fSAndroid Build Coastguard Worker explicit ResizeRootVisitor(const ObjectMap& map) : map_(map) {}
1708*795d594fSAndroid Build Coastguard Worker
1709*795d594fSAndroid Build Coastguard Worker // TODO It's somewhat annoying to have to have this function implemented twice. It might be
1710*795d594fSAndroid Build Coastguard Worker // good/useful to implement operator= for CompressedReference to allow us to use a template to
1711*795d594fSAndroid Build Coastguard Worker // implement both of these.
1712*795d594fSAndroid Build Coastguard Worker void VisitRoots(art::mirror::Object*** roots, size_t count, const art::RootInfo& info) override
1713*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(art::Locks::mutator_lock_) {
1714*795d594fSAndroid Build Coastguard Worker art::mirror::Object*** end = roots + count;
1715*795d594fSAndroid Build Coastguard Worker for (art::mirror::Object** obj = *roots; roots != end; obj = *(++roots)) {
1716*795d594fSAndroid Build Coastguard Worker auto it = map_.find(*obj);
1717*795d594fSAndroid Build Coastguard Worker if (it != map_.end()) {
1718*795d594fSAndroid Build Coastguard Worker // Java frames might have the JIT doing optimizations (for example loop-unrolling or
1719*795d594fSAndroid Build Coastguard Worker // eliding bounds checks) so we need deopt them once we're done here.
1720*795d594fSAndroid Build Coastguard Worker if (info.GetType() == art::RootType::kRootJavaFrame) {
1721*795d594fSAndroid Build Coastguard Worker const art::JavaFrameRootInfo& jfri =
1722*795d594fSAndroid Build Coastguard Worker art::down_cast<const art::JavaFrameRootInfo&>(info);
1723*795d594fSAndroid Build Coastguard Worker if (jfri.GetVReg() == art::JavaFrameRootInfo::kMethodDeclaringClass) {
1724*795d594fSAndroid Build Coastguard Worker info.Describe(VLOG_STREAM(plugin) << "Not changing declaring-class during stack"
1725*795d594fSAndroid Build Coastguard Worker << " walk. Found obsolete java frame id ");
1726*795d594fSAndroid Build Coastguard Worker continue;
1727*795d594fSAndroid Build Coastguard Worker } else {
1728*795d594fSAndroid Build Coastguard Worker info.Describe(VLOG_STREAM(plugin) << "Found java frame id ");
1729*795d594fSAndroid Build Coastguard Worker threads_with_roots_.insert(info.GetThreadId());
1730*795d594fSAndroid Build Coastguard Worker }
1731*795d594fSAndroid Build Coastguard Worker }
1732*795d594fSAndroid Build Coastguard Worker *obj = it->second.Ptr();
1733*795d594fSAndroid Build Coastguard Worker }
1734*795d594fSAndroid Build Coastguard Worker }
1735*795d594fSAndroid Build Coastguard Worker }
1736*795d594fSAndroid Build Coastguard Worker
1737*795d594fSAndroid Build Coastguard Worker void VisitRoots(art::mirror::CompressedReference<art::mirror::Object>** roots,
1738*795d594fSAndroid Build Coastguard Worker size_t count,
1739*795d594fSAndroid Build Coastguard Worker const art::RootInfo& info) override REQUIRES_SHARED(art::Locks::mutator_lock_) {
1740*795d594fSAndroid Build Coastguard Worker art::mirror::CompressedReference<art::mirror::Object>** end = roots + count;
1741*795d594fSAndroid Build Coastguard Worker for (art::mirror::CompressedReference<art::mirror::Object>* obj = *roots; roots != end;
1742*795d594fSAndroid Build Coastguard Worker obj = *(++roots)) {
1743*795d594fSAndroid Build Coastguard Worker auto it = map_.find(obj->AsMirrorPtr());
1744*795d594fSAndroid Build Coastguard Worker if (it != map_.end()) {
1745*795d594fSAndroid Build Coastguard Worker // Java frames might have the JIT doing optimizations (for example loop-unrolling or
1746*795d594fSAndroid Build Coastguard Worker // eliding bounds checks) so we need deopt them once we're done here.
1747*795d594fSAndroid Build Coastguard Worker if (info.GetType() == art::RootType::kRootJavaFrame) {
1748*795d594fSAndroid Build Coastguard Worker const art::JavaFrameRootInfo& jfri =
1749*795d594fSAndroid Build Coastguard Worker art::down_cast<const art::JavaFrameRootInfo&>(info);
1750*795d594fSAndroid Build Coastguard Worker if (jfri.GetVReg() == art::JavaFrameRootInfo::kMethodDeclaringClass) {
1751*795d594fSAndroid Build Coastguard Worker info.Describe(VLOG_STREAM(plugin) << "Not changing declaring-class during stack"
1752*795d594fSAndroid Build Coastguard Worker << " walk. Found obsolete java frame id ");
1753*795d594fSAndroid Build Coastguard Worker continue;
1754*795d594fSAndroid Build Coastguard Worker } else {
1755*795d594fSAndroid Build Coastguard Worker info.Describe(VLOG_STREAM(plugin) << "Found java frame id ");
1756*795d594fSAndroid Build Coastguard Worker threads_with_roots_.insert(info.GetThreadId());
1757*795d594fSAndroid Build Coastguard Worker }
1758*795d594fSAndroid Build Coastguard Worker }
1759*795d594fSAndroid Build Coastguard Worker obj->Assign(it->second);
1760*795d594fSAndroid Build Coastguard Worker }
1761*795d594fSAndroid Build Coastguard Worker }
1762*795d594fSAndroid Build Coastguard Worker }
1763*795d594fSAndroid Build Coastguard Worker
1764*795d594fSAndroid Build Coastguard Worker const std::unordered_set<uint32_t>& GetThreadsWithJavaFrameRoots() const {
1765*795d594fSAndroid Build Coastguard Worker return threads_with_roots_;
1766*795d594fSAndroid Build Coastguard Worker }
1767*795d594fSAndroid Build Coastguard Worker
1768*795d594fSAndroid Build Coastguard Worker private:
1769*795d594fSAndroid Build Coastguard Worker const ObjectMap& map_;
1770*795d594fSAndroid Build Coastguard Worker std::unordered_set<uint32_t> threads_with_roots_;
1771*795d594fSAndroid Build Coastguard Worker };
1772*795d594fSAndroid Build Coastguard Worker ResizeRootVisitor rrv(map);
1773*795d594fSAndroid Build Coastguard Worker art::Runtime::Current()->VisitRoots(&rrv, art::VisitRootFlags::kVisitRootFlagAllRoots);
1774*795d594fSAndroid Build Coastguard Worker // Handle java Frames. Annoyingly the JIT can embed information about the length of the array into
1775*795d594fSAndroid Build Coastguard Worker // the compiled code. By changing the length of the array we potentially invalidate these
1776*795d594fSAndroid Build Coastguard Worker // assumptions and so could cause (eg) OOB array access or other issues.
1777*795d594fSAndroid Build Coastguard Worker if (!rrv.GetThreadsWithJavaFrameRoots().empty()) {
1778*795d594fSAndroid Build Coastguard Worker art::MutexLock mu(self, *art::Locks::thread_list_lock_);
1779*795d594fSAndroid Build Coastguard Worker art::ThreadList* thread_list = art::Runtime::Current()->GetThreadList();
1780*795d594fSAndroid Build Coastguard Worker art::instrumentation::Instrumentation* instr = art::Runtime::Current()->GetInstrumentation();
1781*795d594fSAndroid Build Coastguard Worker for (uint32_t id : rrv.GetThreadsWithJavaFrameRoots()) {
1782*795d594fSAndroid Build Coastguard Worker art::Thread* t = thread_list->FindThreadByThreadId(id);
1783*795d594fSAndroid Build Coastguard Worker CHECK(t != nullptr) << "id " << id << " does not refer to a valid thread."
1784*795d594fSAndroid Build Coastguard Worker << " Where did the roots come from?";
1785*795d594fSAndroid Build Coastguard Worker VLOG(plugin) << "Instrumenting thread stack of thread " << *t;
1786*795d594fSAndroid Build Coastguard Worker // TODO Use deopt manager. We need a version that doesn't acquire all the locks we
1787*795d594fSAndroid Build Coastguard Worker // already have.
1788*795d594fSAndroid Build Coastguard Worker // TODO We technically only need to do this if the frames are not already being interpreted.
1789*795d594fSAndroid Build Coastguard Worker // The cost for doing an extra stack walk is unlikely to be worth it though.
1790*795d594fSAndroid Build Coastguard Worker instr->InstrumentThreadStack(t, /* force_deopt= */ true);
1791*795d594fSAndroid Build Coastguard Worker }
1792*795d594fSAndroid Build Coastguard Worker }
1793*795d594fSAndroid Build Coastguard Worker }
1794*795d594fSAndroid Build Coastguard Worker
ReplaceWeakRoots(art::Thread * self,EventHandler * event_handler,const ObjectMap & map)1795*795d594fSAndroid Build Coastguard Worker static void ReplaceWeakRoots(art::Thread* self,
1796*795d594fSAndroid Build Coastguard Worker EventHandler* event_handler,
1797*795d594fSAndroid Build Coastguard Worker const ObjectMap& map)
1798*795d594fSAndroid Build Coastguard Worker REQUIRES(art::Locks::mutator_lock_, art::Roles::uninterruptible_) {
1799*795d594fSAndroid Build Coastguard Worker // Handle tags. We want to do this seprately from other weak-refs (handled below) because we need
1800*795d594fSAndroid Build Coastguard Worker // to send additional events and handle cases where the agent might have tagged the new
1801*795d594fSAndroid Build Coastguard Worker // replacement object during the VMObjectAlloc. We do this by removing all tags associated with
1802*795d594fSAndroid Build Coastguard Worker // both the obsolete and the new arrays. Then we send the ObsoleteObjectCreated event and cache
1803*795d594fSAndroid Build Coastguard Worker // the new tag values. We next update all the other weak-references (the tags have been removed)
1804*795d594fSAndroid Build Coastguard Worker // and finally update the tag table with the new values. Doing things in this way (1) keeps all
1805*795d594fSAndroid Build Coastguard Worker // code relating to updating weak-references together and (2) ensures we don't end up in strange
1806*795d594fSAndroid Build Coastguard Worker // situations where the order of weak-ref visiting affects the final tagging state. Since we have
1807*795d594fSAndroid Build Coastguard Worker // the mutator_lock_ and gc-paused throughout this whole process no threads should be able to see
1808*795d594fSAndroid Build Coastguard Worker // the interval where the objects are not tagged.
1809*795d594fSAndroid Build Coastguard Worker struct NewTagValue {
1810*795d594fSAndroid Build Coastguard Worker public:
1811*795d594fSAndroid Build Coastguard Worker ObjectPtr obsolete_obj_;
1812*795d594fSAndroid Build Coastguard Worker jlong obsolete_tag_;
1813*795d594fSAndroid Build Coastguard Worker ObjectPtr new_obj_;
1814*795d594fSAndroid Build Coastguard Worker jlong new_tag_;
1815*795d594fSAndroid Build Coastguard Worker };
1816*795d594fSAndroid Build Coastguard Worker
1817*795d594fSAndroid Build Coastguard Worker // Map from the environment to the list of <obsolete_tag, new_tag> pairs that were changed.
1818*795d594fSAndroid Build Coastguard Worker std::unordered_map<ArtJvmTiEnv*, std::vector<NewTagValue>> changed_tags;
1819*795d594fSAndroid Build Coastguard Worker event_handler->ForEachEnv(self, [&](ArtJvmTiEnv* env) {
1820*795d594fSAndroid Build Coastguard Worker // Cannot have REQUIRES(art::Locks::mutator_lock_) since ForEachEnv doesn't require it.
1821*795d594fSAndroid Build Coastguard Worker art::Locks::mutator_lock_->AssertExclusiveHeld(self);
1822*795d594fSAndroid Build Coastguard Worker env->object_tag_table->Lock();
1823*795d594fSAndroid Build Coastguard Worker // Get the tags and clear them (so we don't need to special-case the normal weak-ref visitor)
1824*795d594fSAndroid Build Coastguard Worker for (auto it : map) {
1825*795d594fSAndroid Build Coastguard Worker jlong new_tag = 0;
1826*795d594fSAndroid Build Coastguard Worker jlong obsolete_tag = 0;
1827*795d594fSAndroid Build Coastguard Worker bool had_obsolete_tag = env->object_tag_table->RemoveLocked(it.first, &obsolete_tag);
1828*795d594fSAndroid Build Coastguard Worker bool had_new_tag = env->object_tag_table->RemoveLocked(it.second, &new_tag);
1829*795d594fSAndroid Build Coastguard Worker // Dispatch event.
1830*795d594fSAndroid Build Coastguard Worker if (had_obsolete_tag || had_new_tag) {
1831*795d594fSAndroid Build Coastguard Worker event_handler->DispatchEventOnEnv<ArtJvmtiEvent::kObsoleteObjectCreated>(
1832*795d594fSAndroid Build Coastguard Worker env, self, &obsolete_tag, &new_tag);
1833*795d594fSAndroid Build Coastguard Worker changed_tags.try_emplace(env).first->second.push_back(
1834*795d594fSAndroid Build Coastguard Worker { it.first, obsolete_tag, it.second, new_tag });
1835*795d594fSAndroid Build Coastguard Worker }
1836*795d594fSAndroid Build Coastguard Worker }
1837*795d594fSAndroid Build Coastguard Worker // After weak-ref update we need to go back and re-add obsoletes. We wait to avoid having to
1838*795d594fSAndroid Build Coastguard Worker // deal with the visit-weaks overwriting the initial new_obj_ptr tag and generally making things
1839*795d594fSAndroid Build Coastguard Worker // difficult.
1840*795d594fSAndroid Build Coastguard Worker env->object_tag_table->Unlock();
1841*795d594fSAndroid Build Coastguard Worker });
1842*795d594fSAndroid Build Coastguard Worker // Handle weak-refs.
1843*795d594fSAndroid Build Coastguard Worker struct ReplaceWeaksVisitor : public art::IsMarkedVisitor {
1844*795d594fSAndroid Build Coastguard Worker public:
1845*795d594fSAndroid Build Coastguard Worker ReplaceWeaksVisitor(const ObjectMap& map) : map_(map) {}
1846*795d594fSAndroid Build Coastguard Worker
1847*795d594fSAndroid Build Coastguard Worker art::mirror::Object* IsMarked(art::mirror::Object* obj)
1848*795d594fSAndroid Build Coastguard Worker REQUIRES_SHARED(art::Locks::mutator_lock_) {
1849*795d594fSAndroid Build Coastguard Worker auto it = map_.find(obj);
1850*795d594fSAndroid Build Coastguard Worker if (it != map_.end()) {
1851*795d594fSAndroid Build Coastguard Worker return it->second.Ptr();
1852*795d594fSAndroid Build Coastguard Worker } else {
1853*795d594fSAndroid Build Coastguard Worker return obj;
1854*795d594fSAndroid Build Coastguard Worker }
1855*795d594fSAndroid Build Coastguard Worker }
1856*795d594fSAndroid Build Coastguard Worker
1857*795d594fSAndroid Build Coastguard Worker private:
1858*795d594fSAndroid Build Coastguard Worker const ObjectMap& map_;
1859*795d594fSAndroid Build Coastguard Worker };
1860*795d594fSAndroid Build Coastguard Worker ReplaceWeaksVisitor rwv(map);
1861*795d594fSAndroid Build Coastguard Worker art::Runtime* runtime = art::Runtime::Current();
1862*795d594fSAndroid Build Coastguard Worker runtime->SweepSystemWeaks(&rwv);
1863*795d594fSAndroid Build Coastguard Worker runtime->GetThreadList()->SweepInterpreterCaches(&rwv);
1864*795d594fSAndroid Build Coastguard Worker // Re-add the object tags. At this point all weak-references to the old_obj_ptr are gone.
1865*795d594fSAndroid Build Coastguard Worker event_handler->ForEachEnv(self, [&](ArtJvmTiEnv* env) {
1866*795d594fSAndroid Build Coastguard Worker // Cannot have REQUIRES(art::Locks::mutator_lock_) since ForEachEnv doesn't require it.
1867*795d594fSAndroid Build Coastguard Worker art::Locks::mutator_lock_->AssertExclusiveHeld(self);
1868*795d594fSAndroid Build Coastguard Worker env->object_tag_table->Lock();
1869*795d594fSAndroid Build Coastguard Worker auto it = changed_tags.find(env);
1870*795d594fSAndroid Build Coastguard Worker if (it != changed_tags.end()) {
1871*795d594fSAndroid Build Coastguard Worker for (const NewTagValue& v : it->second) {
1872*795d594fSAndroid Build Coastguard Worker env->object_tag_table->SetLocked(v.obsolete_obj_, v.obsolete_tag_);
1873*795d594fSAndroid Build Coastguard Worker env->object_tag_table->SetLocked(v.new_obj_, v.new_tag_);
1874*795d594fSAndroid Build Coastguard Worker }
1875*795d594fSAndroid Build Coastguard Worker }
1876*795d594fSAndroid Build Coastguard Worker env->object_tag_table->Unlock();
1877*795d594fSAndroid Build Coastguard Worker });
1878*795d594fSAndroid Build Coastguard Worker }
1879*795d594fSAndroid Build Coastguard Worker
1880*795d594fSAndroid Build Coastguard Worker } // namespace
1881*795d594fSAndroid Build Coastguard Worker
ReplaceReference(art::Thread * self,art::ObjPtr<art::mirror::Object> old_obj_ptr,art::ObjPtr<art::mirror::Object> new_obj_ptr)1882*795d594fSAndroid Build Coastguard Worker void HeapExtensions::ReplaceReference(art::Thread* self,
1883*795d594fSAndroid Build Coastguard Worker art::ObjPtr<art::mirror::Object> old_obj_ptr,
1884*795d594fSAndroid Build Coastguard Worker art::ObjPtr<art::mirror::Object> new_obj_ptr) {
1885*795d594fSAndroid Build Coastguard Worker ObjectMap map { { old_obj_ptr, new_obj_ptr } };
1886*795d594fSAndroid Build Coastguard Worker ReplaceReferences(self, map);
1887*795d594fSAndroid Build Coastguard Worker }
1888*795d594fSAndroid Build Coastguard Worker
ReplaceReferences(art::Thread * self,const ObjectMap & map)1889*795d594fSAndroid Build Coastguard Worker void HeapExtensions::ReplaceReferences(art::Thread* self, const ObjectMap& map) {
1890*795d594fSAndroid Build Coastguard Worker ReplaceObjectReferences(map);
1891*795d594fSAndroid Build Coastguard Worker ReplaceStrongRoots(self, map);
1892*795d594fSAndroid Build Coastguard Worker ReplaceWeakRoots(self, HeapExtensions::gEventHandler, map);
1893*795d594fSAndroid Build Coastguard Worker }
1894*795d594fSAndroid Build Coastguard Worker
ChangeArraySize(jvmtiEnv * env,jobject arr,jsize new_size)1895*795d594fSAndroid Build Coastguard Worker jvmtiError HeapExtensions::ChangeArraySize(jvmtiEnv* env, jobject arr, jsize new_size) {
1896*795d594fSAndroid Build Coastguard Worker if (ArtJvmTiEnv::AsArtJvmTiEnv(env)->capabilities.can_tag_objects != 1) {
1897*795d594fSAndroid Build Coastguard Worker return ERR(MUST_POSSESS_CAPABILITY);
1898*795d594fSAndroid Build Coastguard Worker }
1899*795d594fSAndroid Build Coastguard Worker art::Thread* self = art::Thread::Current();
1900*795d594fSAndroid Build Coastguard Worker ScopedNoUserCodeSuspension snucs(self);
1901*795d594fSAndroid Build Coastguard Worker art::ScopedObjectAccess soa(self);
1902*795d594fSAndroid Build Coastguard Worker if (arr == nullptr) {
1903*795d594fSAndroid Build Coastguard Worker JVMTI_LOG(INFO, env) << "Cannot resize a null object";
1904*795d594fSAndroid Build Coastguard Worker return ERR(NULL_POINTER);
1905*795d594fSAndroid Build Coastguard Worker }
1906*795d594fSAndroid Build Coastguard Worker art::ObjPtr<art::mirror::Class> klass(soa.Decode<art::mirror::Object>(arr)->GetClass());
1907*795d594fSAndroid Build Coastguard Worker if (!klass->IsArrayClass()) {
1908*795d594fSAndroid Build Coastguard Worker JVMTI_LOG(INFO, env) << klass->PrettyClass() << " is not an array class!";
1909*795d594fSAndroid Build Coastguard Worker return ERR(ILLEGAL_ARGUMENT);
1910*795d594fSAndroid Build Coastguard Worker }
1911*795d594fSAndroid Build Coastguard Worker if (new_size < 0) {
1912*795d594fSAndroid Build Coastguard Worker JVMTI_LOG(INFO, env) << "Cannot resize an array to a negative size";
1913*795d594fSAndroid Build Coastguard Worker return ERR(ILLEGAL_ARGUMENT);
1914*795d594fSAndroid Build Coastguard Worker }
1915*795d594fSAndroid Build Coastguard Worker // Allocate the new copy.
1916*795d594fSAndroid Build Coastguard Worker art::StackHandleScope<2> hs(self);
1917*795d594fSAndroid Build Coastguard Worker art::Handle<art::mirror::Array> old_arr(hs.NewHandle(soa.Decode<art::mirror::Array>(arr)));
1918*795d594fSAndroid Build Coastguard Worker art::MutableHandle<art::mirror::Array> new_arr(hs.NewHandle<art::mirror::Array>(nullptr));
1919*795d594fSAndroid Build Coastguard Worker if (klass->IsObjectArrayClass()) {
1920*795d594fSAndroid Build Coastguard Worker new_arr.Assign(
1921*795d594fSAndroid Build Coastguard Worker art::mirror::ObjectArray<art::mirror::Object>::Alloc(self, old_arr->GetClass(), new_size));
1922*795d594fSAndroid Build Coastguard Worker } else {
1923*795d594fSAndroid Build Coastguard Worker // NB This also copies the old array but since we aren't suspended we need to do this again to
1924*795d594fSAndroid Build Coastguard Worker // catch any concurrent modifications.
1925*795d594fSAndroid Build Coastguard Worker new_arr.Assign(art::mirror::Array::CopyOf(old_arr, self, new_size));
1926*795d594fSAndroid Build Coastguard Worker }
1927*795d594fSAndroid Build Coastguard Worker if (new_arr.IsNull()) {
1928*795d594fSAndroid Build Coastguard Worker self->AssertPendingOOMException();
1929*795d594fSAndroid Build Coastguard Worker JVMTI_LOG(INFO, env) << "Unable to allocate " << old_arr->GetClass()->PrettyClass()
1930*795d594fSAndroid Build Coastguard Worker << " (length: " << new_size << ") due to OOME. Error was: "
1931*795d594fSAndroid Build Coastguard Worker << self->GetException()->Dump();
1932*795d594fSAndroid Build Coastguard Worker self->ClearException();
1933*795d594fSAndroid Build Coastguard Worker return ERR(OUT_OF_MEMORY);
1934*795d594fSAndroid Build Coastguard Worker } else {
1935*795d594fSAndroid Build Coastguard Worker self->AssertNoPendingException();
1936*795d594fSAndroid Build Coastguard Worker }
1937*795d594fSAndroid Build Coastguard Worker // Suspend everything.
1938*795d594fSAndroid Build Coastguard Worker art::ScopedThreadSuspension sts(self, art::ThreadState::kSuspended);
1939*795d594fSAndroid Build Coastguard Worker art::gc::ScopedGCCriticalSection sgccs(
1940*795d594fSAndroid Build Coastguard Worker self, art::gc::GcCause::kGcCauseDebugger, art::gc::CollectorType::kCollectorTypeDebugger);
1941*795d594fSAndroid Build Coastguard Worker art::ScopedSuspendAll ssa("Resize array!");
1942*795d594fSAndroid Build Coastguard Worker // Replace internals.
1943*795d594fSAndroid Build Coastguard Worker new_arr->SetLockWord(old_arr->GetLockWord(false), false);
1944*795d594fSAndroid Build Coastguard Worker old_arr->SetLockWord(art::LockWord::Default(), false);
1945*795d594fSAndroid Build Coastguard Worker // Copy the contents now when everything is suspended.
1946*795d594fSAndroid Build Coastguard Worker int32_t size = std::min(old_arr->GetLength(), new_size);
1947*795d594fSAndroid Build Coastguard Worker switch (old_arr->GetClass()->GetComponentType()->GetPrimitiveType()) {
1948*795d594fSAndroid Build Coastguard Worker case art::Primitive::kPrimBoolean:
1949*795d594fSAndroid Build Coastguard Worker new_arr->AsBooleanArray()->Memcpy(0, old_arr->AsBooleanArray(), 0, size);
1950*795d594fSAndroid Build Coastguard Worker break;
1951*795d594fSAndroid Build Coastguard Worker case art::Primitive::kPrimByte:
1952*795d594fSAndroid Build Coastguard Worker new_arr->AsByteArray()->Memcpy(0, old_arr->AsByteArray(), 0, size);
1953*795d594fSAndroid Build Coastguard Worker break;
1954*795d594fSAndroid Build Coastguard Worker case art::Primitive::kPrimChar:
1955*795d594fSAndroid Build Coastguard Worker new_arr->AsCharArray()->Memcpy(0, old_arr->AsCharArray(), 0, size);
1956*795d594fSAndroid Build Coastguard Worker break;
1957*795d594fSAndroid Build Coastguard Worker case art::Primitive::kPrimShort:
1958*795d594fSAndroid Build Coastguard Worker new_arr->AsShortArray()->Memcpy(0, old_arr->AsShortArray(), 0, size);
1959*795d594fSAndroid Build Coastguard Worker break;
1960*795d594fSAndroid Build Coastguard Worker case art::Primitive::kPrimInt:
1961*795d594fSAndroid Build Coastguard Worker new_arr->AsIntArray()->Memcpy(0, old_arr->AsIntArray(), 0, size);
1962*795d594fSAndroid Build Coastguard Worker break;
1963*795d594fSAndroid Build Coastguard Worker case art::Primitive::kPrimLong:
1964*795d594fSAndroid Build Coastguard Worker new_arr->AsLongArray()->Memcpy(0, old_arr->AsLongArray(), 0, size);
1965*795d594fSAndroid Build Coastguard Worker break;
1966*795d594fSAndroid Build Coastguard Worker case art::Primitive::kPrimFloat:
1967*795d594fSAndroid Build Coastguard Worker new_arr->AsFloatArray()->Memcpy(0, old_arr->AsFloatArray(), 0, size);
1968*795d594fSAndroid Build Coastguard Worker break;
1969*795d594fSAndroid Build Coastguard Worker case art::Primitive::kPrimDouble:
1970*795d594fSAndroid Build Coastguard Worker new_arr->AsDoubleArray()->Memcpy(0, old_arr->AsDoubleArray(), 0, size);
1971*795d594fSAndroid Build Coastguard Worker break;
1972*795d594fSAndroid Build Coastguard Worker case art::Primitive::kPrimNot:
1973*795d594fSAndroid Build Coastguard Worker for (int32_t i = 0; i < size; i++) {
1974*795d594fSAndroid Build Coastguard Worker new_arr->AsObjectArray<art::mirror::Object>()->Set(
1975*795d594fSAndroid Build Coastguard Worker i, old_arr->AsObjectArray<art::mirror::Object>()->Get(i));
1976*795d594fSAndroid Build Coastguard Worker }
1977*795d594fSAndroid Build Coastguard Worker break;
1978*795d594fSAndroid Build Coastguard Worker case art::Primitive::kPrimVoid:
1979*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "void-array is not a legal type!";
1980*795d594fSAndroid Build Coastguard Worker UNREACHABLE();
1981*795d594fSAndroid Build Coastguard Worker }
1982*795d594fSAndroid Build Coastguard Worker // Actually replace all the pointers.
1983*795d594fSAndroid Build Coastguard Worker ReplaceReference(self, old_arr.Get(), new_arr.Get());
1984*795d594fSAndroid Build Coastguard Worker return OK;
1985*795d594fSAndroid Build Coastguard Worker }
1986*795d594fSAndroid Build Coastguard Worker
Register(EventHandler * eh)1987*795d594fSAndroid Build Coastguard Worker void HeapExtensions::Register(EventHandler* eh) {
1988*795d594fSAndroid Build Coastguard Worker gEventHandler = eh;
1989*795d594fSAndroid Build Coastguard Worker }
1990*795d594fSAndroid Build Coastguard Worker
1991*795d594fSAndroid Build Coastguard Worker } // namespace openjdkjvmti
1992