blob: 79a8cd630421af65ef976e9d7d5925b0d9977223 [file] [log] [blame]
Alex Light3f33c0a2017-11-08 10:17:37 -08001/* Copyright (C) 2017 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 <vector>
33
34#include "ti_extension.h"
35
36#include "art_jvmti.h"
Alex Light8c2b9292017-11-09 13:21:01 -080037#include "events.h"
Alex Light3f33c0a2017-11-08 10:17:37 -080038#include "ti_allocator.h"
Alex Light8c2b9292017-11-09 13:21:01 -080039#include "ti_ddms.h"
Alex Light3f33c0a2017-11-08 10:17:37 -080040#include "ti_heap.h"
Alex Light8c2b9292017-11-09 13:21:01 -080041#include "thread-inl.h"
Alex Light3f33c0a2017-11-08 10:17:37 -080042
43namespace openjdkjvmti {
44
45struct CParamInfo {
46 const char* name;
47 jvmtiParamKind kind;
48 jvmtiParamTypes base_type;
49 jboolean null_ok;
50
51 jvmtiParamInfo ToParamInfo(jvmtiEnv* env,
52 /*out*/std::vector<JvmtiUniquePtr<char[]>>* char_buffers,
53 /*out*/jvmtiError* err) const {
54 JvmtiUniquePtr<char[]> param_name = CopyString(env, name, err);
55 char* name_ptr = param_name.get();
56 char_buffers->push_back(std::move(param_name));
Igor Murashkin5573c372017-11-16 13:34:30 -080057 return jvmtiParamInfo{ name_ptr, kind, base_type, null_ok };
Alex Light3f33c0a2017-11-08 10:17:37 -080058 }
59};
60
61jvmtiError ExtensionUtil::GetExtensionFunctions(jvmtiEnv* env,
62 jint* extension_count_ptr,
63 jvmtiExtensionFunctionInfo** extensions) {
64 if (extension_count_ptr == nullptr || extensions == nullptr) {
65 return ERR(NULL_POINTER);
66 }
67
68 std::vector<jvmtiExtensionFunctionInfo> ext_vector;
69
70 // Holders for allocated values.
71 std::vector<JvmtiUniquePtr<char[]>> char_buffers;
72 std::vector<JvmtiUniquePtr<jvmtiParamInfo[]>> param_buffers;
73 std::vector<JvmtiUniquePtr<jvmtiError[]>> error_buffers;
74
75 auto add_extension = [&](jvmtiExtensionFunction func,
76 const char* id,
77 const char* short_description,
78 const std::vector<CParamInfo>& params,
79 const std::vector<jvmtiError>& errors) {
80 jvmtiExtensionFunctionInfo func_info;
81 jvmtiError error;
82
83 func_info.func = func;
84
85 JvmtiUniquePtr<char[]> id_ptr = CopyString(env, id, &error);
86 if (id_ptr == nullptr) {
87 return error;
88 }
89 func_info.id = id_ptr.get();
90 char_buffers.push_back(std::move(id_ptr));
91
92 JvmtiUniquePtr<char[]> descr = CopyString(env, short_description, &error);
93 if (descr == nullptr) {
94 return error;
95 }
96 func_info.short_description = descr.get();
97 char_buffers.push_back(std::move(descr));
98
99 func_info.param_count = params.size();
100 if (!params.empty()) {
101 JvmtiUniquePtr<jvmtiParamInfo[]> params_ptr =
102 AllocJvmtiUniquePtr<jvmtiParamInfo[]>(env, params.size(), &error);
103 if (params_ptr == nullptr) {
104 return error;
105 }
106 func_info.params = params_ptr.get();
107 param_buffers.push_back(std::move(params_ptr));
108
109 for (jint i = 0; i != func_info.param_count; ++i) {
110 func_info.params[i] = params[i].ToParamInfo(env, &char_buffers, &error);
111 if (error != OK) {
112 return error;
113 }
114 }
115 } else {
116 func_info.params = nullptr;
117 }
118
119 func_info.error_count = errors.size();
120 if (!errors.empty()) {
121 JvmtiUniquePtr<jvmtiError[]> errors_ptr =
122 AllocJvmtiUniquePtr<jvmtiError[]>(env, errors.size(), &error);
123 if (errors_ptr == nullptr) {
124 return error;
125 }
126 func_info.errors = errors_ptr.get();
127 error_buffers.push_back(std::move(errors_ptr));
128
129 for (jint i = 0; i != func_info.error_count; ++i) {
130 func_info.errors[i] = errors[i];
131 }
132 } else {
133 func_info.errors = nullptr;
134 }
135
136 ext_vector.push_back(func_info);
137
138 return ERR(NONE);
139 };
140
141 jvmtiError error;
142
143 // Heap extensions.
144 error = add_extension(
145 reinterpret_cast<jvmtiExtensionFunction>(HeapExtensions::GetObjectHeapId),
146 "com.android.art.heap.get_object_heap_id",
147 "Retrieve the heap id of the the object tagged with the given argument. An "
148 "arbitrary object is chosen if multiple objects exist with the same tag.",
Igor Murashkin5573c372017-11-16 13:34:30 -0800149 {
Alex Light3f33c0a2017-11-08 10:17:37 -0800150 { "tag", JVMTI_KIND_IN, JVMTI_TYPE_JLONG, false},
151 { "heap_id", JVMTI_KIND_OUT, JVMTI_TYPE_JINT, false}
152 },
153 { JVMTI_ERROR_NOT_FOUND });
154 if (error != ERR(NONE)) {
155 return error;
156 }
157
158 error = add_extension(
159 reinterpret_cast<jvmtiExtensionFunction>(HeapExtensions::GetHeapName),
160 "com.android.art.heap.get_heap_name",
161 "Retrieve the name of the heap with the given id.",
Igor Murashkin5573c372017-11-16 13:34:30 -0800162 {
Alex Light3f33c0a2017-11-08 10:17:37 -0800163 { "heap_id", JVMTI_KIND_IN, JVMTI_TYPE_JINT, false},
164 { "heap_name", JVMTI_KIND_ALLOC_BUF, JVMTI_TYPE_CCHAR, false}
165 },
166 { JVMTI_ERROR_ILLEGAL_ARGUMENT });
167 if (error != ERR(NONE)) {
168 return error;
169 }
170
171 error = add_extension(
172 reinterpret_cast<jvmtiExtensionFunction>(HeapExtensions::IterateThroughHeapExt),
173 "com.android.art.heap.iterate_through_heap_ext",
174 "Iterate through a heap. This is equivalent to the standard IterateThroughHeap function,"
175 " except for additionally passing the heap id of the current object. The jvmtiHeapCallbacks"
176 " structure is reused, with the callbacks field overloaded to a signature of "
177 "jint (*)(jlong, jlong, jlong*, jint length, void*, jint).",
Igor Murashkin5573c372017-11-16 13:34:30 -0800178 {
Alex Light3f33c0a2017-11-08 10:17:37 -0800179 { "heap_filter", JVMTI_KIND_IN, JVMTI_TYPE_JINT, false},
180 { "klass", JVMTI_KIND_IN, JVMTI_TYPE_JCLASS, true},
181 { "callbacks", JVMTI_KIND_IN_PTR, JVMTI_TYPE_CVOID, false},
182 { "user_data", JVMTI_KIND_IN_PTR, JVMTI_TYPE_CVOID, true}
183 },
Igor Murashkin5573c372017-11-16 13:34:30 -0800184 {
Alex Light3f33c0a2017-11-08 10:17:37 -0800185 ERR(MUST_POSSESS_CAPABILITY),
186 ERR(INVALID_CLASS),
187 ERR(NULL_POINTER),
188 });
189 if (error != ERR(NONE)) {
190 return error;
191 }
192
193 error = add_extension(
194 reinterpret_cast<jvmtiExtensionFunction>(AllocUtil::GetGlobalJvmtiAllocationState),
195 "com.android.art.alloc.get_global_jvmti_allocation_state",
196 "Returns the total amount of memory currently allocated by all jvmtiEnvs through the"
197 " 'Allocate' jvmti function. This does not include any memory that has been deallocated"
198 " through the 'Deallocate' function. This number is approximate and might not correspond"
199 " exactly to the sum of the sizes of all not freed allocations.",
Igor Murashkin5573c372017-11-16 13:34:30 -0800200 {
Alex Light3f33c0a2017-11-08 10:17:37 -0800201 { "currently_allocated", JVMTI_KIND_OUT, JVMTI_TYPE_JLONG, false},
202 },
203 { ERR(NULL_POINTER) });
204 if (error != ERR(NONE)) {
205 return error;
206 }
207
Alex Light8c2b9292017-11-09 13:21:01 -0800208 // DDMS extension
209 error = add_extension(
210 reinterpret_cast<jvmtiExtensionFunction>(DDMSUtil::HandleChunk),
211 "com.android.art.internal.ddm.process_chunk",
212 "Handles a single ddms chunk request and returns a response. The reply data is in the ddms"
213 " chunk format. It returns the processed chunk. This is provided for backwards compatibility"
214 " reasons only. Agents should avoid making use of this extension when possible and instead"
215 " use the other JVMTI entrypoints explicitly.",
Igor Murashkin5573c372017-11-16 13:34:30 -0800216 {
Alex Light8c2b9292017-11-09 13:21:01 -0800217 { "type_in", JVMTI_KIND_IN, JVMTI_TYPE_JINT, false },
218 { "length_in", JVMTI_KIND_IN, JVMTI_TYPE_JINT, false },
Alex Light6f2a6342017-12-12 09:55:05 -0800219 { "data_in", JVMTI_KIND_IN_BUF, JVMTI_TYPE_JBYTE, true },
Alex Light8c2b9292017-11-09 13:21:01 -0800220 { "type_out", JVMTI_KIND_OUT, JVMTI_TYPE_JINT, false },
221 { "data_len_out", JVMTI_KIND_OUT, JVMTI_TYPE_JINT, false },
222 { "data_out", JVMTI_KIND_ALLOC_BUF, JVMTI_TYPE_JBYTE, false }
223 },
224 { ERR(NULL_POINTER), ERR(ILLEGAL_ARGUMENT), ERR(OUT_OF_MEMORY) });
225 if (error != ERR(NONE)) {
226 return error;
227 }
228
Alex Light3f33c0a2017-11-08 10:17:37 -0800229 // Copy into output buffer.
230
231 *extension_count_ptr = ext_vector.size();
232 JvmtiUniquePtr<jvmtiExtensionFunctionInfo[]> out_data =
233 AllocJvmtiUniquePtr<jvmtiExtensionFunctionInfo[]>(env, ext_vector.size(), &error);
234 if (out_data == nullptr) {
235 return error;
236 }
237 memcpy(out_data.get(),
238 ext_vector.data(),
239 ext_vector.size() * sizeof(jvmtiExtensionFunctionInfo));
240 *extensions = out_data.release();
241
242 // Release all the buffer holders, we're OK now.
243 for (auto& holder : char_buffers) {
244 holder.release();
245 }
246 for (auto& holder : param_buffers) {
247 holder.release();
248 }
249 for (auto& holder : error_buffers) {
250 holder.release();
251 }
252
253 return OK;
254}
255
256
Alex Light8c2b9292017-11-09 13:21:01 -0800257jvmtiError ExtensionUtil::GetExtensionEvents(jvmtiEnv* env,
Alex Light3f33c0a2017-11-08 10:17:37 -0800258 jint* extension_count_ptr,
259 jvmtiExtensionEventInfo** extensions) {
Alex Light8c2b9292017-11-09 13:21:01 -0800260 std::vector<jvmtiExtensionEventInfo> ext_vector;
261
262 // Holders for allocated values.
263 std::vector<JvmtiUniquePtr<char[]>> char_buffers;
264 std::vector<JvmtiUniquePtr<jvmtiParamInfo[]>> param_buffers;
265
266 auto add_extension = [&](ArtJvmtiEvent extension_event_index,
267 const char* id,
268 const char* short_description,
269 const std::vector<CParamInfo>& params) {
270 DCHECK(IsExtensionEvent(extension_event_index));
271 jvmtiExtensionEventInfo event_info;
272 jvmtiError error;
273
274 event_info.extension_event_index = static_cast<jint>(extension_event_index);
275
276 JvmtiUniquePtr<char[]> id_ptr = CopyString(env, id, &error);
277 if (id_ptr == nullptr) {
278 return error;
279 }
280 event_info.id = id_ptr.get();
281 char_buffers.push_back(std::move(id_ptr));
282
283 JvmtiUniquePtr<char[]> descr = CopyString(env, short_description, &error);
284 if (descr == nullptr) {
285 return error;
286 }
287 event_info.short_description = descr.get();
288 char_buffers.push_back(std::move(descr));
289
290 event_info.param_count = params.size();
291 if (!params.empty()) {
292 JvmtiUniquePtr<jvmtiParamInfo[]> params_ptr =
293 AllocJvmtiUniquePtr<jvmtiParamInfo[]>(env, params.size(), &error);
294 if (params_ptr == nullptr) {
295 return error;
296 }
297 event_info.params = params_ptr.get();
298 param_buffers.push_back(std::move(params_ptr));
299
300 for (jint i = 0; i != event_info.param_count; ++i) {
301 event_info.params[i] = params[i].ToParamInfo(env, &char_buffers, &error);
302 if (error != OK) {
303 return error;
304 }
305 }
306 } else {
307 event_info.params = nullptr;
308 }
309
310 ext_vector.push_back(event_info);
311
312 return ERR(NONE);
313 };
314
315 jvmtiError error;
316 error = add_extension(
317 ArtJvmtiEvent::kDdmPublishChunk,
318 "com.android.art.internal.ddm.publish_chunk",
319 "Called when there is new ddms information that the agent or other clients can use. The"
320 " agent is given the 'type' of the ddms chunk and a 'data_size' byte-buffer in 'data'."
321 " The 'data' pointer is only valid for the duration of the publish_chunk event. The agent"
322 " is responsible for interpreting the information present in the 'data' buffer. This is"
323 " provided for backwards-compatibility support only. Agents should prefer to use relevant"
324 " JVMTI events and functions above listening for this event.",
Igor Murashkin5573c372017-11-16 13:34:30 -0800325 {
Alex Light8c2b9292017-11-09 13:21:01 -0800326 { "jni_env", JVMTI_KIND_IN_PTR, JVMTI_TYPE_JNIENV, false },
327 { "type", JVMTI_KIND_IN, JVMTI_TYPE_JINT, false },
328 { "data_size", JVMTI_KIND_IN, JVMTI_TYPE_JINT, false },
329 { "data", JVMTI_KIND_IN_BUF, JVMTI_TYPE_JBYTE, false },
330 });
331 if (error != OK) {
332 return error;
333 }
334
335 // Copy into output buffer.
336
337 *extension_count_ptr = ext_vector.size();
338 JvmtiUniquePtr<jvmtiExtensionEventInfo[]> out_data =
339 AllocJvmtiUniquePtr<jvmtiExtensionEventInfo[]>(env, ext_vector.size(), &error);
340 if (out_data == nullptr) {
341 return error;
342 }
343 memcpy(out_data.get(),
344 ext_vector.data(),
345 ext_vector.size() * sizeof(jvmtiExtensionEventInfo));
346 *extensions = out_data.release();
347
348 // Release all the buffer holders, we're OK now.
349 for (auto& holder : char_buffers) {
350 holder.release();
351 }
352 for (auto& holder : param_buffers) {
353 holder.release();
354 }
355
Alex Light3f33c0a2017-11-08 10:17:37 -0800356 return OK;
357}
358
Alex Light8c2b9292017-11-09 13:21:01 -0800359jvmtiError ExtensionUtil::SetExtensionEventCallback(jvmtiEnv* env,
360 jint extension_event_index,
361 jvmtiExtensionEvent callback,
362 EventHandler* event_handler) {
363 if (!IsExtensionEvent(extension_event_index)) {
364 return ERR(ILLEGAL_ARGUMENT);
365 }
366 ArtJvmTiEnv* art_env = ArtJvmTiEnv::AsArtJvmTiEnv(env);
367 jvmtiEventMode mode = callback == nullptr ? JVMTI_DISABLE : JVMTI_ENABLE;
368 // Lock the event_info_mutex_ while we set the event to make sure it isn't lost by a concurrent
369 // change to the normal callbacks.
370 {
371 art::WriterMutexLock lk(art::Thread::Current(), art_env->event_info_mutex_);
372 if (art_env->event_callbacks.get() == nullptr) {
373 art_env->event_callbacks.reset(new ArtJvmtiEventCallbacks());
374 }
375 jvmtiError err = art_env->event_callbacks->Set(extension_event_index, callback);
376 if (err != OK) {
377 return err;
378 }
379 }
380 return event_handler->SetEvent(art_env,
381 /*event_thread*/nullptr,
382 static_cast<ArtJvmtiEvent>(extension_event_index),
383 mode);
Alex Light3f33c0a2017-11-08 10:17:37 -0800384}
385
386} // namespace openjdkjvmti