blob: 0d1704ca4d3e46b4b9a804d12c6711406cbd8220 [file] [log] [blame]
Andreas Gampee492ae32016-10-28 19:34:57 -07001/* Copyright (C) 2016 The Android Open Source Project
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3 *
4 * This file implements interfaces from the file jvmti.h. This implementation
5 * is licensed under the same terms as the file jvmti.h. The
6 * copyright and license information for the file jvmti.h follows.
7 *
8 * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
9 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
10 *
11 * This code is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License version 2 only, as
13 * published by the Free Software Foundation. Oracle designates this
14 * particular file as subject to the "Classpath" exception as provided
15 * by Oracle in the LICENSE file that accompanied this code.
16 *
17 * This code is distributed in the hope that it will be useful, but WITHOUT
18 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 * version 2 for more details (a copy is included in the LICENSE file that
21 * accompanied this code).
22 *
23 * You should have received a copy of the GNU General Public License version
24 * 2 along with this work; if not, write to the Free Software Foundation,
25 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
26 *
27 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
28 * or visit www.oracle.com if you need additional information or have any
29 * questions.
30 */
31
32#include "ti_class.h"
33
34#include "art_jvmti.h"
Andreas Gampeac587272017-01-05 15:21:34 -080035#include "jni_internal.h"
Andreas Gampee492ae32016-10-28 19:34:57 -070036#include "scoped_thread_state_change-inl.h"
37#include "thread-inl.h"
38
39namespace openjdkjvmti {
40
Andreas Gampeac587272017-01-05 15:21:34 -080041jvmtiError ClassUtil::GetClassFields(jvmtiEnv* env,
42 jclass jklass,
43 jint* field_count_ptr,
44 jfieldID** fields_ptr) {
45 art::ScopedObjectAccess soa(art::Thread::Current());
46 art::ObjPtr<art::mirror::Class> klass = soa.Decode<art::mirror::Class>(jklass);
47 if (klass == nullptr) {
48 return ERR(INVALID_CLASS);
49 }
50
51 if (field_count_ptr == nullptr || fields_ptr == nullptr) {
52 return ERR(NULL_POINTER);
53 }
54
Andreas Gampeac587272017-01-05 15:21:34 -080055 art::IterationRange<art::StrideIterator<art::ArtField>> ifields = klass->GetIFields();
56 art::IterationRange<art::StrideIterator<art::ArtField>> sfields = klass->GetSFields();
57 size_t array_size = klass->NumInstanceFields() + klass->NumStaticFields();
58
59 unsigned char* out_ptr;
60 jvmtiError allocError = env->Allocate(array_size * sizeof(jfieldID), &out_ptr);
61 if (allocError != ERR(NONE)) {
62 return allocError;
63 }
64 jfieldID* field_array = reinterpret_cast<jfieldID*>(out_ptr);
65
66 size_t array_idx = 0;
67 for (art::ArtField& field : sfields) {
68 field_array[array_idx] = art::jni::EncodeArtField(&field);
69 ++array_idx;
70 }
71 for (art::ArtField& field : ifields) {
72 field_array[array_idx] = art::jni::EncodeArtField(&field);
73 ++array_idx;
74 }
75
76 *field_count_ptr = static_cast<jint>(array_size);
77 *fields_ptr = field_array;
78
79 return ERR(NONE);
80}
81
Andreas Gampe18fee4d2017-01-06 11:36:35 -080082jvmtiError ClassUtil::GetClassMethods(jvmtiEnv* env,
83 jclass jklass,
84 jint* method_count_ptr,
85 jmethodID** methods_ptr) {
86 art::ScopedObjectAccess soa(art::Thread::Current());
87 art::ObjPtr<art::mirror::Class> klass = soa.Decode<art::mirror::Class>(jklass);
88 if (klass == nullptr) {
89 return ERR(INVALID_CLASS);
90 }
91
92 if (method_count_ptr == nullptr || methods_ptr == nullptr) {
93 return ERR(NULL_POINTER);
94 }
95
96 size_t array_size = klass->NumDeclaredVirtualMethods() + klass->NumDirectMethods();
97 unsigned char* out_ptr;
98 jvmtiError allocError = env->Allocate(array_size * sizeof(jmethodID), &out_ptr);
99 if (allocError != ERR(NONE)) {
100 return allocError;
101 }
102 jmethodID* method_array = reinterpret_cast<jmethodID*>(out_ptr);
103
104 if (art::kIsDebugBuild) {
105 size_t count = 0;
106 for (auto& m ATTRIBUTE_UNUSED : klass->GetDeclaredMethods(art::kRuntimePointerSize)) {
107 count++;
108 }
109 CHECK_EQ(count, klass->NumDirectMethods() + klass->NumDeclaredVirtualMethods());
110 }
111
112 size_t array_idx = 0;
113 for (auto& m : klass->GetDeclaredMethods(art::kRuntimePointerSize)) {
114 method_array[array_idx] = art::jni::EncodeArtMethod(&m);
115 ++array_idx;
116 }
117
118 *method_count_ptr = static_cast<jint>(array_size);
119 *methods_ptr = method_array;
120
121 return ERR(NONE);
122}
123
Andreas Gampe8b07e472017-01-06 14:20:39 -0800124jvmtiError ClassUtil::GetImplementedInterfaces(jvmtiEnv* env,
125 jclass jklass,
126 jint* interface_count_ptr,
127 jclass** interfaces_ptr) {
128 art::ScopedObjectAccess soa(art::Thread::Current());
129 art::ObjPtr<art::mirror::Class> klass = soa.Decode<art::mirror::Class>(jklass);
130 if (klass == nullptr) {
131 return ERR(INVALID_CLASS);
132 }
133
134 if (interface_count_ptr == nullptr || interfaces_ptr == nullptr) {
135 return ERR(NULL_POINTER);
136 }
137
138 // Need to handle array specifically. Arrays implement Serializable and Cloneable, but the
139 // spec says these should not be reported.
140 if (klass->IsArrayClass()) {
141 *interface_count_ptr = 0;
142 *interfaces_ptr = nullptr; // TODO: Should we allocate a dummy here?
143 return ERR(NONE);
144 }
145
146 size_t array_size = klass->NumDirectInterfaces();
147 unsigned char* out_ptr;
148 jvmtiError allocError = env->Allocate(array_size * sizeof(jclass), &out_ptr);
149 if (allocError != ERR(NONE)) {
150 return allocError;
151 }
152 jclass* interface_array = reinterpret_cast<jclass*>(out_ptr);
153
154 art::StackHandleScope<1> hs(soa.Self());
155 art::Handle<art::mirror::Class> h_klass(hs.NewHandle(klass));
156
157 for (uint32_t idx = 0; idx != array_size; ++idx) {
158 art::ObjPtr<art::mirror::Class> inf_klass =
159 art::mirror::Class::ResolveDirectInterface(soa.Self(), h_klass, idx);
160 if (inf_klass == nullptr) {
161 soa.Self()->ClearException();
162 env->Deallocate(out_ptr);
163 // TODO: What is the right error code here?
164 return ERR(INTERNAL);
165 }
166 interface_array[idx] = soa.AddLocalReference<jclass>(inf_klass);
167 }
168
169 *interface_count_ptr = static_cast<jint>(array_size);
170 *interfaces_ptr = interface_array;
171
172 return ERR(NONE);
173}
Andreas Gampe18fee4d2017-01-06 11:36:35 -0800174
Andreas Gampee492ae32016-10-28 19:34:57 -0700175jvmtiError ClassUtil::GetClassSignature(jvmtiEnv* env,
176 jclass jklass,
177 char** signature_ptr,
178 char** generic_ptr) {
179 art::ScopedObjectAccess soa(art::Thread::Current());
180 art::ObjPtr<art::mirror::Class> klass = soa.Decode<art::mirror::Class>(jklass);
181 if (klass == nullptr) {
182 return ERR(INVALID_CLASS);
183 }
184
185 JvmtiUniquePtr sig_copy;
186 if (signature_ptr != nullptr) {
187 std::string storage;
188 const char* descriptor = klass->GetDescriptor(&storage);
189
190 unsigned char* tmp;
191 jvmtiError ret = CopyString(env, descriptor, &tmp);
192 if (ret != ERR(NONE)) {
193 return ret;
194 }
195 sig_copy = MakeJvmtiUniquePtr(env, tmp);
196 *signature_ptr = reinterpret_cast<char*>(tmp);
197 }
198
199 // TODO: Support generic signature.
200 *generic_ptr = nullptr;
201
202 // Everything is fine, release the buffers.
203 sig_copy.release();
204
205 return ERR(NONE);
206}
207
Andreas Gampeff9d2092017-01-06 09:12:49 -0800208jvmtiError ClassUtil::GetClassStatus(jvmtiEnv* env ATTRIBUTE_UNUSED,
209 jclass jklass,
210 jint* status_ptr) {
211 art::ScopedObjectAccess soa(art::Thread::Current());
212 art::ObjPtr<art::mirror::Class> klass = soa.Decode<art::mirror::Class>(jklass);
213 if (klass == nullptr) {
214 return ERR(INVALID_CLASS);
215 }
216
217 if (status_ptr == nullptr) {
218 return ERR(NULL_POINTER);
219 }
220
221 if (klass->IsArrayClass()) {
222 *status_ptr = JVMTI_CLASS_STATUS_ARRAY;
223 } else if (klass->IsPrimitive()) {
224 *status_ptr = JVMTI_CLASS_STATUS_PRIMITIVE;
225 } else {
226 *status_ptr = JVMTI_CLASS_STATUS_VERIFIED; // All loaded classes are structurally verified.
227 // This is finicky. If there's an error, we'll say it wasn't prepared.
228 if (klass->IsResolved()) {
229 *status_ptr |= JVMTI_CLASS_STATUS_PREPARED;
230 }
231 if (klass->IsInitialized()) {
232 *status_ptr |= JVMTI_CLASS_STATUS_INITIALIZED;
233 }
234 // Technically the class may be erroneous for other reasons, but we do not have enough info.
235 if (klass->IsErroneous()) {
236 *status_ptr |= JVMTI_CLASS_STATUS_ERROR;
237 }
238 }
239
240 return ERR(NONE);
241}
242
Andreas Gampe4fd66ec2017-01-05 14:42:13 -0800243template <typename T>
244static jvmtiError ClassIsT(jclass jklass, T test, jboolean* is_t_ptr) {
245 art::ScopedObjectAccess soa(art::Thread::Current());
246 art::ObjPtr<art::mirror::Class> klass = soa.Decode<art::mirror::Class>(jklass);
247 if (klass == nullptr) {
248 return ERR(INVALID_CLASS);
249 }
250
251 if (is_t_ptr == nullptr) {
252 return ERR(NULL_POINTER);
253 }
254
255 *is_t_ptr = test(klass) ? JNI_TRUE : JNI_FALSE;
256 return ERR(NONE);
257}
258
259jvmtiError ClassUtil::IsInterface(jvmtiEnv* env ATTRIBUTE_UNUSED,
260 jclass jklass,
261 jboolean* is_interface_ptr) {
262 auto test = [](art::ObjPtr<art::mirror::Class> klass) REQUIRES_SHARED(art::Locks::mutator_lock_) {
263 return klass->IsInterface();
264 };
265 return ClassIsT(jklass, test, is_interface_ptr);
266}
267
268jvmtiError ClassUtil::IsArrayClass(jvmtiEnv* env ATTRIBUTE_UNUSED,
269 jclass jklass,
270 jboolean* is_array_class_ptr) {
271 auto test = [](art::ObjPtr<art::mirror::Class> klass) REQUIRES_SHARED(art::Locks::mutator_lock_) {
272 return klass->IsArrayClass();
273 };
274 return ClassIsT(jklass, test, is_array_class_ptr);
275}
276
Andreas Gampe64013e52017-01-06 13:07:19 -0800277// Keep this in sync with Class.getModifiers().
278static uint32_t ClassGetModifiers(art::Thread* self, art::ObjPtr<art::mirror::Class> klass)
279 REQUIRES_SHARED(art::Locks::mutator_lock_) {
280 if (klass->IsArrayClass()) {
281 uint32_t component_modifiers = ClassGetModifiers(self, klass->GetComponentType());
282 if ((component_modifiers & art::kAccInterface) != 0) {
283 component_modifiers &= ~(art::kAccInterface | art::kAccStatic);
284 }
285 return art::kAccAbstract | art::kAccFinal | component_modifiers;
286 }
287
288 uint32_t modifiers = klass->GetAccessFlags() & art::kAccJavaFlagsMask;
289
290 art::StackHandleScope<1> hs(self);
291 art::Handle<art::mirror::Class> h_klass(hs.NewHandle(klass));
292 return art::mirror::Class::GetInnerClassFlags(h_klass, modifiers);
293}
294
295jvmtiError ClassUtil::GetClassModifiers(jvmtiEnv* env ATTRIBUTE_UNUSED,
296 jclass jklass,
297 jint* modifiers_ptr) {
298 art::ScopedObjectAccess soa(art::Thread::Current());
299 art::ObjPtr<art::mirror::Class> klass = soa.Decode<art::mirror::Class>(jklass);
300 if (klass == nullptr) {
301 return ERR(INVALID_CLASS);
302 }
303
304 if (modifiers_ptr == nullptr) {
305 return ERR(NULL_POINTER);
306 }
307
308 *modifiers_ptr = ClassGetModifiers(soa.Self(), klass);
309
310 return ERR(NONE);
311}
312
Andreas Gampe8f5b6032017-01-06 15:50:55 -0800313jvmtiError ClassUtil::GetClassLoader(jvmtiEnv* env ATTRIBUTE_UNUSED,
314 jclass jklass,
315 jobject* classloader_ptr) {
316 art::ScopedObjectAccess soa(art::Thread::Current());
317 art::ObjPtr<art::mirror::Class> klass = soa.Decode<art::mirror::Class>(jklass);
318 if (klass == nullptr) {
319 return ERR(INVALID_CLASS);
320 }
321
322 if (classloader_ptr == nullptr) {
323 return ERR(NULL_POINTER);
324 }
325
326 *classloader_ptr = soa.AddLocalReference<jobject>(klass->GetClassLoader());
327
328 return ERR(NONE);
329}
330
Andreas Gampee492ae32016-10-28 19:34:57 -0700331} // namespace openjdkjvmti