blob: fbed9640a006b6f598612140619f80500e0d0f3d [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"
37#include "ti_allocator.h"
38#include "ti_heap.h"
39
40namespace openjdkjvmti {
41
42struct CParamInfo {
43 const char* name;
44 jvmtiParamKind kind;
45 jvmtiParamTypes base_type;
46 jboolean null_ok;
47
48 jvmtiParamInfo ToParamInfo(jvmtiEnv* env,
49 /*out*/std::vector<JvmtiUniquePtr<char[]>>* char_buffers,
50 /*out*/jvmtiError* err) const {
51 JvmtiUniquePtr<char[]> param_name = CopyString(env, name, err);
52 char* name_ptr = param_name.get();
53 char_buffers->push_back(std::move(param_name));
54 return jvmtiParamInfo { name_ptr, kind, base_type, null_ok }; // NOLINT [whitespace/braces] [4]
55 }
56};
57
58jvmtiError ExtensionUtil::GetExtensionFunctions(jvmtiEnv* env,
59 jint* extension_count_ptr,
60 jvmtiExtensionFunctionInfo** extensions) {
61 if (extension_count_ptr == nullptr || extensions == nullptr) {
62 return ERR(NULL_POINTER);
63 }
64
65 std::vector<jvmtiExtensionFunctionInfo> ext_vector;
66
67 // Holders for allocated values.
68 std::vector<JvmtiUniquePtr<char[]>> char_buffers;
69 std::vector<JvmtiUniquePtr<jvmtiParamInfo[]>> param_buffers;
70 std::vector<JvmtiUniquePtr<jvmtiError[]>> error_buffers;
71
72 auto add_extension = [&](jvmtiExtensionFunction func,
73 const char* id,
74 const char* short_description,
75 const std::vector<CParamInfo>& params,
76 const std::vector<jvmtiError>& errors) {
77 jvmtiExtensionFunctionInfo func_info;
78 jvmtiError error;
79
80 func_info.func = func;
81
82 JvmtiUniquePtr<char[]> id_ptr = CopyString(env, id, &error);
83 if (id_ptr == nullptr) {
84 return error;
85 }
86 func_info.id = id_ptr.get();
87 char_buffers.push_back(std::move(id_ptr));
88
89 JvmtiUniquePtr<char[]> descr = CopyString(env, short_description, &error);
90 if (descr == nullptr) {
91 return error;
92 }
93 func_info.short_description = descr.get();
94 char_buffers.push_back(std::move(descr));
95
96 func_info.param_count = params.size();
97 if (!params.empty()) {
98 JvmtiUniquePtr<jvmtiParamInfo[]> params_ptr =
99 AllocJvmtiUniquePtr<jvmtiParamInfo[]>(env, params.size(), &error);
100 if (params_ptr == nullptr) {
101 return error;
102 }
103 func_info.params = params_ptr.get();
104 param_buffers.push_back(std::move(params_ptr));
105
106 for (jint i = 0; i != func_info.param_count; ++i) {
107 func_info.params[i] = params[i].ToParamInfo(env, &char_buffers, &error);
108 if (error != OK) {
109 return error;
110 }
111 }
112 } else {
113 func_info.params = nullptr;
114 }
115
116 func_info.error_count = errors.size();
117 if (!errors.empty()) {
118 JvmtiUniquePtr<jvmtiError[]> errors_ptr =
119 AllocJvmtiUniquePtr<jvmtiError[]>(env, errors.size(), &error);
120 if (errors_ptr == nullptr) {
121 return error;
122 }
123 func_info.errors = errors_ptr.get();
124 error_buffers.push_back(std::move(errors_ptr));
125
126 for (jint i = 0; i != func_info.error_count; ++i) {
127 func_info.errors[i] = errors[i];
128 }
129 } else {
130 func_info.errors = nullptr;
131 }
132
133 ext_vector.push_back(func_info);
134
135 return ERR(NONE);
136 };
137
138 jvmtiError error;
139
140 // Heap extensions.
141 error = add_extension(
142 reinterpret_cast<jvmtiExtensionFunction>(HeapExtensions::GetObjectHeapId),
143 "com.android.art.heap.get_object_heap_id",
144 "Retrieve the heap id of the the object tagged with the given argument. An "
145 "arbitrary object is chosen if multiple objects exist with the same tag.",
146 { // NOLINT [whitespace/braces] [4]
147 { "tag", JVMTI_KIND_IN, JVMTI_TYPE_JLONG, false},
148 { "heap_id", JVMTI_KIND_OUT, JVMTI_TYPE_JINT, false}
149 },
150 { JVMTI_ERROR_NOT_FOUND });
151 if (error != ERR(NONE)) {
152 return error;
153 }
154
155 error = add_extension(
156 reinterpret_cast<jvmtiExtensionFunction>(HeapExtensions::GetHeapName),
157 "com.android.art.heap.get_heap_name",
158 "Retrieve the name of the heap with the given id.",
159 { // NOLINT [whitespace/braces] [4]
160 { "heap_id", JVMTI_KIND_IN, JVMTI_TYPE_JINT, false},
161 { "heap_name", JVMTI_KIND_ALLOC_BUF, JVMTI_TYPE_CCHAR, false}
162 },
163 { JVMTI_ERROR_ILLEGAL_ARGUMENT });
164 if (error != ERR(NONE)) {
165 return error;
166 }
167
168 error = add_extension(
169 reinterpret_cast<jvmtiExtensionFunction>(HeapExtensions::IterateThroughHeapExt),
170 "com.android.art.heap.iterate_through_heap_ext",
171 "Iterate through a heap. This is equivalent to the standard IterateThroughHeap function,"
172 " except for additionally passing the heap id of the current object. The jvmtiHeapCallbacks"
173 " structure is reused, with the callbacks field overloaded to a signature of "
174 "jint (*)(jlong, jlong, jlong*, jint length, void*, jint).",
175 { // NOLINT [whitespace/braces] [4]
176 { "heap_filter", JVMTI_KIND_IN, JVMTI_TYPE_JINT, false},
177 { "klass", JVMTI_KIND_IN, JVMTI_TYPE_JCLASS, true},
178 { "callbacks", JVMTI_KIND_IN_PTR, JVMTI_TYPE_CVOID, false},
179 { "user_data", JVMTI_KIND_IN_PTR, JVMTI_TYPE_CVOID, true}
180 },
181 { // NOLINT [whitespace/braces] [4]
182 ERR(MUST_POSSESS_CAPABILITY),
183 ERR(INVALID_CLASS),
184 ERR(NULL_POINTER),
185 });
186 if (error != ERR(NONE)) {
187 return error;
188 }
189
190 error = add_extension(
191 reinterpret_cast<jvmtiExtensionFunction>(AllocUtil::GetGlobalJvmtiAllocationState),
192 "com.android.art.alloc.get_global_jvmti_allocation_state",
193 "Returns the total amount of memory currently allocated by all jvmtiEnvs through the"
194 " 'Allocate' jvmti function. This does not include any memory that has been deallocated"
195 " through the 'Deallocate' function. This number is approximate and might not correspond"
196 " exactly to the sum of the sizes of all not freed allocations.",
197 { // NOLINT [whitespace/braces] [4]
198 { "currently_allocated", JVMTI_KIND_OUT, JVMTI_TYPE_JLONG, false},
199 },
200 { ERR(NULL_POINTER) });
201 if (error != ERR(NONE)) {
202 return error;
203 }
204
205 // Copy into output buffer.
206
207 *extension_count_ptr = ext_vector.size();
208 JvmtiUniquePtr<jvmtiExtensionFunctionInfo[]> out_data =
209 AllocJvmtiUniquePtr<jvmtiExtensionFunctionInfo[]>(env, ext_vector.size(), &error);
210 if (out_data == nullptr) {
211 return error;
212 }
213 memcpy(out_data.get(),
214 ext_vector.data(),
215 ext_vector.size() * sizeof(jvmtiExtensionFunctionInfo));
216 *extensions = out_data.release();
217
218 // Release all the buffer holders, we're OK now.
219 for (auto& holder : char_buffers) {
220 holder.release();
221 }
222 for (auto& holder : param_buffers) {
223 holder.release();
224 }
225 for (auto& holder : error_buffers) {
226 holder.release();
227 }
228
229 return OK;
230}
231
232
233jvmtiError ExtensionUtil::GetExtensionEvents(jvmtiEnv* env ATTRIBUTE_UNUSED,
234 jint* extension_count_ptr,
235 jvmtiExtensionEventInfo** extensions) {
236 // We don't have any extension events at the moment.
237 *extension_count_ptr = 0;
238 *extensions = nullptr;
239 return OK;
240}
241
242jvmtiError ExtensionUtil::SetExtensionEventCallback(jvmtiEnv* env ATTRIBUTE_UNUSED,
243 jint extension_event_index ATTRIBUTE_UNUSED,
244 jvmtiExtensionEvent callback ATTRIBUTE_UNUSED) {
245 // We do not have any extension events, so any call is illegal.
246 return ERR(ILLEGAL_ARGUMENT);
247}
248
249} // namespace openjdkjvmti