blob: 83d64ef1d8e7e8ba00a15332d0d17c66c671c9a3 [file] [log] [blame]
Andreas Gampe3c252f02016-10-27 18:25:17 -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_method.h"
33
Andreas Gampe49fc60e2017-08-24 13:19:59 -070034#include <type_traits>
35
Andreas Gampe3c252f02016-10-27 18:25:17 -070036#include "art_jvmti.h"
37#include "art_method-inl.h"
38#include "base/enums.h"
Alex Lightbebd7bd2017-07-25 14:05:52 -070039#include "base/mutex-inl.h"
David Sehr9e734c72018-01-04 17:56:19 -080040#include "dex/code_item_accessors-inl.h"
41#include "dex/dex_file_annotations.h"
42#include "dex/dex_file_types.h"
David Sehr8c0961f2018-01-23 16:11:38 -080043#include "dex/modifiers.h"
Alex Lightd78ddec2017-04-18 15:20:38 -070044#include "events-inl.h"
Alex Light0a5ec3d2017-07-25 16:50:26 -070045#include "jit/jit.h"
Andreas Gampe13b27842016-11-07 16:48:23 -080046#include "jni_internal.h"
Alex Lightbebd7bd2017-07-25 14:05:52 -070047#include "mirror/class-inl.h"
48#include "mirror/class_loader.h"
49#include "mirror/object-inl.h"
Andreas Gampe27dfa052017-02-16 15:04:36 -080050#include "mirror/object_array-inl.h"
Andreas Gampe373a9b52017-10-18 09:01:57 -070051#include "nativehelper/scoped_local_ref.h"
Nicolas Geoffray58cc1cb2017-11-20 13:27:29 +000052#include "oat_file.h"
Alex Lightd78ddec2017-04-18 15:20:38 -070053#include "runtime_callbacks.h"
Andreas Gampe3c252f02016-10-27 18:25:17 -070054#include "scoped_thread_state_change-inl.h"
Alex Lightbebd7bd2017-07-25 14:05:52 -070055#include "stack.h"
Andreas Gampeb486a982017-06-01 13:45:54 -070056#include "thread-current-inl.h"
Alex Lightd78ddec2017-04-18 15:20:38 -070057#include "thread_list.h"
Alex Lighte814f9d2017-07-31 16:14:39 -070058#include "ti_stack.h"
Alex Lightbebd7bd2017-07-25 14:05:52 -070059#include "ti_thread.h"
Alex Light0af8cde2017-04-20 13:35:05 -070060#include "ti_phase.h"
Andreas Gampe3c252f02016-10-27 18:25:17 -070061
62namespace openjdkjvmti {
63
Alex Lightd78ddec2017-04-18 15:20:38 -070064struct TiMethodCallback : public art::MethodCallback {
65 void RegisterNativeMethod(art::ArtMethod* method,
66 const void* cur_method,
67 /*out*/void** new_method)
68 OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) {
69 if (event_handler->IsEventEnabledAnywhere(ArtJvmtiEvent::kNativeMethodBind)) {
70 art::Thread* thread = art::Thread::Current();
Alex Light0af8cde2017-04-20 13:35:05 -070071 art::JNIEnvExt* jnienv = thread->GetJniEnv();
Alex Lightd78ddec2017-04-18 15:20:38 -070072 ScopedLocalRef<jthread> thread_jni(
Alex Light0af8cde2017-04-20 13:35:05 -070073 jnienv, PhaseUtil::IsLivePhase() ? jnienv->AddLocalReference<jthread>(thread->GetPeer())
74 : nullptr);
Alex Lightd78ddec2017-04-18 15:20:38 -070075 art::ScopedThreadSuspension sts(thread, art::ThreadState::kNative);
76 event_handler->DispatchEvent<ArtJvmtiEvent::kNativeMethodBind>(
77 thread,
Alex Light0af8cde2017-04-20 13:35:05 -070078 static_cast<JNIEnv*>(jnienv),
Alex Lightd78ddec2017-04-18 15:20:38 -070079 thread_jni.get(),
80 art::jni::EncodeArtMethod(method),
81 const_cast<void*>(cur_method),
82 new_method);
83 }
84 }
85
86 EventHandler* event_handler = nullptr;
87};
88
89TiMethodCallback gMethodCallback;
90
91void MethodUtil::Register(EventHandler* handler) {
92 gMethodCallback.event_handler = handler;
93 art::ScopedThreadStateChange stsc(art::Thread::Current(),
94 art::ThreadState::kWaitingForDebuggerToAttach);
95 art::ScopedSuspendAll ssa("Add method callback");
Alex Light21611932017-09-26 13:07:39 -070096 art::RuntimeCallbacks* callbacks = art::Runtime::Current()->GetRuntimeCallbacks();
97 callbacks->AddMethodCallback(&gMethodCallback);
Alex Lightd78ddec2017-04-18 15:20:38 -070098}
99
100void MethodUtil::Unregister() {
101 art::ScopedThreadStateChange stsc(art::Thread::Current(),
102 art::ThreadState::kWaitingForDebuggerToAttach);
103 art::ScopedSuspendAll ssa("Remove method callback");
Alex Light21611932017-09-26 13:07:39 -0700104 art::RuntimeCallbacks* callbacks = art::Runtime::Current()->GetRuntimeCallbacks();
105 callbacks->RemoveMethodCallback(&gMethodCallback);
Alex Lightd78ddec2017-04-18 15:20:38 -0700106}
107
Alex Light4c174282017-07-05 10:18:18 -0700108jvmtiError MethodUtil::GetBytecodes(jvmtiEnv* env,
109 jmethodID method,
110 jint* size_ptr,
111 unsigned char** bytecode_ptr) {
112 if (method == nullptr) {
113 return ERR(INVALID_METHODID);
114 }
115 art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
116
117 if (art_method->IsNative()) {
118 return ERR(NATIVE_METHOD);
119 }
120
121 if (size_ptr == nullptr || bytecode_ptr == nullptr) {
122 return ERR(NULL_POINTER);
123 }
124
125 art::ScopedObjectAccess soa(art::Thread::Current());
David Sehr0225f8e2018-01-31 08:52:24 +0000126 art::CodeItemInstructionAccessor accessor(art_method->DexInstructions());
Mathieu Chartier808c7a52017-12-15 11:19:33 -0800127 if (!accessor.HasCodeItem()) {
Alex Light4c174282017-07-05 10:18:18 -0700128 *size_ptr = 0;
129 *bytecode_ptr = nullptr;
130 return OK;
131 }
132 // 2 bytes per instruction for dex code.
Mathieu Chartier808c7a52017-12-15 11:19:33 -0800133 *size_ptr = accessor.InsnsSizeInCodeUnits() * 2;
Alex Light4c174282017-07-05 10:18:18 -0700134 jvmtiError err = env->Allocate(*size_ptr, bytecode_ptr);
135 if (err != OK) {
136 return err;
137 }
Mathieu Chartier808c7a52017-12-15 11:19:33 -0800138 memcpy(*bytecode_ptr, accessor.Insns(), *size_ptr);
Alex Light4c174282017-07-05 10:18:18 -0700139 return OK;
140}
141
Andreas Gampef71832e2017-01-09 11:38:04 -0800142jvmtiError MethodUtil::GetArgumentsSize(jvmtiEnv* env ATTRIBUTE_UNUSED,
143 jmethodID method,
144 jint* size_ptr) {
145 if (method == nullptr) {
146 return ERR(INVALID_METHODID);
147 }
148 art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
149
150 if (art_method->IsNative()) {
151 return ERR(NATIVE_METHOD);
152 }
153
154 if (size_ptr == nullptr) {
155 return ERR(NULL_POINTER);
156 }
157
158 art::ScopedObjectAccess soa(art::Thread::Current());
159 if (art_method->IsProxyMethod() || art_method->IsAbstract()) {
Andreas Gampee1f79b62017-04-12 21:11:28 -0700160 // Use the shorty.
161 art::ArtMethod* base_method = art_method->GetInterfaceMethodIfProxy(art::kRuntimePointerSize);
162 size_t arg_count = art::ArtMethod::NumArgRegisters(base_method->GetShorty());
163 if (!base_method->IsStatic()) {
164 arg_count++;
165 }
166 *size_ptr = static_cast<jint>(arg_count);
Andreas Gampef71832e2017-01-09 11:38:04 -0800167 return ERR(NONE);
168 }
169
170 DCHECK_NE(art_method->GetCodeItemOffset(), 0u);
David Sehr0225f8e2018-01-31 08:52:24 +0000171 *size_ptr = art_method->DexInstructionData().InsSize();
Andreas Gampef71832e2017-01-09 11:38:04 -0800172
173 return ERR(NONE);
174}
175
Alex Lightce68cc62017-07-26 10:30:38 -0700176jvmtiError MethodUtil::GetLocalVariableTable(jvmtiEnv* env,
177 jmethodID method,
178 jint* entry_count_ptr,
179 jvmtiLocalVariableEntry** table_ptr) {
180 if (method == nullptr) {
181 return ERR(INVALID_METHODID);
182 }
183 art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
184
185 if (art_method->IsNative()) {
186 return ERR(NATIVE_METHOD);
187 }
188
189 if (entry_count_ptr == nullptr || table_ptr == nullptr) {
190 return ERR(NULL_POINTER);
191 }
192
193 art::ScopedObjectAccess soa(art::Thread::Current());
Mathieu Chartier31f4c9f2017-12-08 15:46:11 -0800194
195 const art::DexFile* const dex_file = art_method->GetDexFile();
196 if (dex_file == nullptr) {
197 return ERR(ABSENT_INFORMATION);
198 }
199
200 // TODO HasCodeItem == false means that the method is abstract (or native, but we check that
Alex Lightce68cc62017-07-26 10:30:38 -0700201 // earlier). We should check what is returned by the RI in this situation since it's not clear
202 // what the appropriate return value is from the spec.
David Sehr0225f8e2018-01-31 08:52:24 +0000203 art::CodeItemDebugInfoAccessor accessor(art_method->DexInstructionDebugInfo());
Mathieu Chartier31f4c9f2017-12-08 15:46:11 -0800204 if (!accessor.HasCodeItem()) {
Alex Lightce68cc62017-07-26 10:30:38 -0700205 return ERR(ABSENT_INFORMATION);
206 }
207
208 struct LocalVariableContext {
209 explicit LocalVariableContext(jvmtiEnv* jenv) : env_(jenv), variables_(), err_(OK) {}
210
211 static void Callback(void* raw_ctx, const art::DexFile::LocalInfo& entry) {
212 reinterpret_cast<LocalVariableContext*>(raw_ctx)->Insert(entry);
213 }
214
215 void Insert(const art::DexFile::LocalInfo& entry) {
216 if (err_ != OK) {
217 return;
218 }
219 JvmtiUniquePtr<char[]> name_str = CopyString(env_, entry.name_, &err_);
220 if (err_ != OK) {
221 return;
222 }
223 JvmtiUniquePtr<char[]> sig_str = CopyString(env_, entry.descriptor_, &err_);
224 if (err_ != OK) {
225 return;
226 }
227 JvmtiUniquePtr<char[]> generic_sig_str = CopyString(env_, entry.signature_, &err_);
228 if (err_ != OK) {
229 return;
230 }
231 variables_.push_back({
232 .start_location = static_cast<jlocation>(entry.start_address_),
233 .length = static_cast<jint>(entry.end_address_ - entry.start_address_),
234 .name = name_str.release(),
235 .signature = sig_str.release(),
236 .generic_signature = generic_sig_str.release(),
237 .slot = entry.reg_,
238 });
239 }
240
241 jvmtiError Release(jint* out_entry_count_ptr, jvmtiLocalVariableEntry** out_table_ptr) {
242 jlong table_size = sizeof(jvmtiLocalVariableEntry) * variables_.size();
243 if (err_ != OK ||
244 (err_ = env_->Allocate(table_size,
245 reinterpret_cast<unsigned char**>(out_table_ptr))) != OK) {
246 Cleanup();
247 return err_;
248 } else {
249 *out_entry_count_ptr = variables_.size();
250 memcpy(*out_table_ptr, variables_.data(), table_size);
251 return OK;
252 }
253 }
254
255 void Cleanup() {
256 for (jvmtiLocalVariableEntry& e : variables_) {
257 env_->Deallocate(reinterpret_cast<unsigned char*>(e.name));
258 env_->Deallocate(reinterpret_cast<unsigned char*>(e.signature));
259 env_->Deallocate(reinterpret_cast<unsigned char*>(e.generic_signature));
260 }
261 }
262
263 jvmtiEnv* env_;
264 std::vector<jvmtiLocalVariableEntry> variables_;
265 jvmtiError err_;
266 };
267
268 LocalVariableContext context(env);
Mathieu Chartier808c7a52017-12-15 11:19:33 -0800269 if (!accessor.DecodeDebugLocalInfo(art_method->IsStatic(),
270 art_method->GetDexMethodIndex(),
271 LocalVariableContext::Callback,
272 &context)) {
Alex Lightce68cc62017-07-26 10:30:38 -0700273 // Something went wrong with decoding the debug information. It might as well not be there.
274 return ERR(ABSENT_INFORMATION);
275 } else {
276 return context.Release(entry_count_ptr, table_ptr);
277 }
278}
279
Andreas Gampef71832e2017-01-09 11:38:04 -0800280jvmtiError MethodUtil::GetMaxLocals(jvmtiEnv* env ATTRIBUTE_UNUSED,
281 jmethodID method,
282 jint* max_ptr) {
283 if (method == nullptr) {
284 return ERR(INVALID_METHODID);
285 }
286 art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
287
288 if (art_method->IsNative()) {
289 return ERR(NATIVE_METHOD);
290 }
291
292 if (max_ptr == nullptr) {
293 return ERR(NULL_POINTER);
294 }
295
296 art::ScopedObjectAccess soa(art::Thread::Current());
297 if (art_method->IsProxyMethod() || art_method->IsAbstract()) {
298 // This isn't specified as an error case, so return 0.
299 *max_ptr = 0;
300 return ERR(NONE);
301 }
302
303 DCHECK_NE(art_method->GetCodeItemOffset(), 0u);
David Sehr0225f8e2018-01-31 08:52:24 +0000304 *max_ptr = art_method->DexInstructionData().RegistersSize();
Andreas Gampef71832e2017-01-09 11:38:04 -0800305
306 return ERR(NONE);
307}
308
Andreas Gampe3c252f02016-10-27 18:25:17 -0700309jvmtiError MethodUtil::GetMethodName(jvmtiEnv* env,
310 jmethodID method,
311 char** name_ptr,
312 char** signature_ptr,
313 char** generic_ptr) {
314 art::ScopedObjectAccess soa(art::Thread::Current());
Andreas Gampe13b27842016-11-07 16:48:23 -0800315 art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
Andreas Gampe3c252f02016-10-27 18:25:17 -0700316 art_method = art_method->GetInterfaceMethodIfProxy(art::kRuntimePointerSize);
317
Andreas Gampe54711412017-02-21 12:41:43 -0800318 JvmtiUniquePtr<char[]> name_copy;
Andreas Gampe3c252f02016-10-27 18:25:17 -0700319 if (name_ptr != nullptr) {
320 const char* method_name = art_method->GetName();
321 if (method_name == nullptr) {
322 method_name = "<error>";
323 }
Andreas Gampe54711412017-02-21 12:41:43 -0800324 jvmtiError ret;
325 name_copy = CopyString(env, method_name, &ret);
326 if (name_copy == nullptr) {
Andreas Gampe3c252f02016-10-27 18:25:17 -0700327 return ret;
328 }
Andreas Gampe54711412017-02-21 12:41:43 -0800329 *name_ptr = name_copy.get();
Andreas Gampe3c252f02016-10-27 18:25:17 -0700330 }
331
Andreas Gampe54711412017-02-21 12:41:43 -0800332 JvmtiUniquePtr<char[]> signature_copy;
Andreas Gampe3c252f02016-10-27 18:25:17 -0700333 if (signature_ptr != nullptr) {
334 const art::Signature sig = art_method->GetSignature();
335 std::string str = sig.ToString();
Andreas Gampe54711412017-02-21 12:41:43 -0800336 jvmtiError ret;
337 signature_copy = CopyString(env, str.c_str(), &ret);
338 if (signature_copy == nullptr) {
Andreas Gampe3c252f02016-10-27 18:25:17 -0700339 return ret;
340 }
Andreas Gampe54711412017-02-21 12:41:43 -0800341 *signature_ptr = signature_copy.get();
Andreas Gampe3c252f02016-10-27 18:25:17 -0700342 }
343
Andreas Gampe862bdd82016-11-18 13:31:13 -0800344 if (generic_ptr != nullptr) {
345 *generic_ptr = nullptr;
Andreas Gampe27dfa052017-02-16 15:04:36 -0800346 if (!art_method->GetDeclaringClass()->IsProxyClass()) {
347 art::mirror::ObjectArray<art::mirror::String>* str_array =
348 art::annotations::GetSignatureAnnotationForMethod(art_method);
349 if (str_array != nullptr) {
350 std::ostringstream oss;
351 for (int32_t i = 0; i != str_array->GetLength(); ++i) {
352 oss << str_array->Get(i)->ToModifiedUtf8();
353 }
354 std::string output_string = oss.str();
Andreas Gampe54711412017-02-21 12:41:43 -0800355 jvmtiError ret;
356 JvmtiUniquePtr<char[]> generic_copy = CopyString(env, output_string.c_str(), &ret);
357 if (generic_copy == nullptr) {
Andreas Gampe27dfa052017-02-16 15:04:36 -0800358 return ret;
359 }
Andreas Gampe54711412017-02-21 12:41:43 -0800360 *generic_ptr = generic_copy.release();
Andreas Gampe27dfa052017-02-16 15:04:36 -0800361 } else if (soa.Self()->IsExceptionPending()) {
362 // TODO: Should we report an error here?
363 soa.Self()->ClearException();
364 }
365 }
Andreas Gampe862bdd82016-11-18 13:31:13 -0800366 }
Andreas Gampe3c252f02016-10-27 18:25:17 -0700367
368 // Everything is fine, release the buffers.
369 name_copy.release();
370 signature_copy.release();
371
372 return ERR(NONE);
373}
374
Andreas Gampe368a2082016-10-28 17:33:13 -0700375jvmtiError MethodUtil::GetMethodDeclaringClass(jvmtiEnv* env ATTRIBUTE_UNUSED,
376 jmethodID method,
377 jclass* declaring_class_ptr) {
378 if (declaring_class_ptr == nullptr) {
379 return ERR(NULL_POINTER);
380 }
381
Andreas Gampe13b27842016-11-07 16:48:23 -0800382 art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
Andreas Gampe368a2082016-10-28 17:33:13 -0700383 // Note: No GetInterfaceMethodIfProxy, we want to actual class.
384
Andreas Gampe13b27842016-11-07 16:48:23 -0800385 art::ScopedObjectAccess soa(art::Thread::Current());
Andreas Gampe368a2082016-10-28 17:33:13 -0700386 art::mirror::Class* klass = art_method->GetDeclaringClass();
387 *declaring_class_ptr = soa.AddLocalReference<jclass>(klass);
388
389 return ERR(NONE);
390}
391
Andreas Gampef71832e2017-01-09 11:38:04 -0800392jvmtiError MethodUtil::GetMethodLocation(jvmtiEnv* env ATTRIBUTE_UNUSED,
393 jmethodID method,
394 jlocation* start_location_ptr,
395 jlocation* end_location_ptr) {
396 if (method == nullptr) {
397 return ERR(INVALID_METHODID);
398 }
399 art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
400
401 if (art_method->IsNative()) {
402 return ERR(NATIVE_METHOD);
403 }
404
405 if (start_location_ptr == nullptr || end_location_ptr == nullptr) {
406 return ERR(NULL_POINTER);
407 }
408
409 art::ScopedObjectAccess soa(art::Thread::Current());
410 if (art_method->IsProxyMethod() || art_method->IsAbstract()) {
Andreas Gampee1f79b62017-04-12 21:11:28 -0700411 // This isn't specified as an error case, so return -1/-1 as the RI does.
412 *start_location_ptr = -1;
413 *end_location_ptr = -1;
Andreas Gampef71832e2017-01-09 11:38:04 -0800414 return ERR(NONE);
415 }
416
417 DCHECK_NE(art_method->GetCodeItemOffset(), 0u);
418 *start_location_ptr = 0;
Mathieu Chartier808c7a52017-12-15 11:19:33 -0800419 *end_location_ptr = art_method->DexInstructions().InsnsSizeInCodeUnits() - 1;
Andreas Gampef71832e2017-01-09 11:38:04 -0800420
421 return ERR(NONE);
422}
423
Andreas Gampe36bcd4f2016-10-28 18:07:18 -0700424jvmtiError MethodUtil::GetMethodModifiers(jvmtiEnv* env ATTRIBUTE_UNUSED,
425 jmethodID method,
426 jint* modifiers_ptr) {
427 if (modifiers_ptr == nullptr) {
428 return ERR(NULL_POINTER);
429 }
430
Andreas Gampe13b27842016-11-07 16:48:23 -0800431 art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
Andreas Gampe36bcd4f2016-10-28 18:07:18 -0700432 uint32_t modifiers = art_method->GetAccessFlags();
433
434 // Note: Keep this code in sync with Executable.fixMethodFlags.
435 if ((modifiers & art::kAccAbstract) != 0) {
436 modifiers &= ~art::kAccNative;
437 }
438 modifiers &= ~art::kAccSynchronized;
439 if ((modifiers & art::kAccDeclaredSynchronized) != 0) {
440 modifiers |= art::kAccSynchronized;
441 }
442 modifiers &= art::kAccJavaFlagsMask;
443
444 *modifiers_ptr = modifiers;
445 return ERR(NONE);
446}
447
Andreas Gampeda3e5612016-12-13 19:00:53 -0800448using LineNumberContext = std::vector<jvmtiLineNumberEntry>;
449
450static bool CollectLineNumbers(void* void_context, const art::DexFile::PositionInfo& entry) {
451 LineNumberContext* context = reinterpret_cast<LineNumberContext*>(void_context);
452 jvmtiLineNumberEntry jvmti_entry = { static_cast<jlocation>(entry.address_),
453 static_cast<jint>(entry.line_) };
454 context->push_back(jvmti_entry);
455 return false; // Collect all, no early exit.
456}
457
458jvmtiError MethodUtil::GetLineNumberTable(jvmtiEnv* env,
459 jmethodID method,
460 jint* entry_count_ptr,
461 jvmtiLineNumberEntry** table_ptr) {
462 if (method == nullptr) {
463 return ERR(NULL_POINTER);
464 }
465 art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
466 DCHECK(!art_method->IsRuntimeMethod());
467
Mathieu Chartier31f4c9f2017-12-08 15:46:11 -0800468 art::CodeItemDebugInfoAccessor accessor;
Andreas Gampeda3e5612016-12-13 19:00:53 -0800469 const art::DexFile* dex_file;
470 {
471 art::ScopedObjectAccess soa(art::Thread::Current());
472
473 if (art_method->IsProxyMethod()) {
474 return ERR(ABSENT_INFORMATION);
475 }
476 if (art_method->IsNative()) {
477 return ERR(NATIVE_METHOD);
478 }
479 if (entry_count_ptr == nullptr || table_ptr == nullptr) {
480 return ERR(NULL_POINTER);
481 }
482
David Sehr0225f8e2018-01-31 08:52:24 +0000483 accessor = art::CodeItemDebugInfoAccessor(art_method->DexInstructionDebugInfo());
Andreas Gampeda3e5612016-12-13 19:00:53 -0800484 dex_file = art_method->GetDexFile();
Mathieu Chartier31f4c9f2017-12-08 15:46:11 -0800485 DCHECK(accessor.HasCodeItem()) << art_method->PrettyMethod() << " " << dex_file->GetLocation();
Andreas Gampeda3e5612016-12-13 19:00:53 -0800486 }
487
488 LineNumberContext context;
Nicolas Geoffray58cc1cb2017-11-20 13:27:29 +0000489 bool success = dex_file->DecodeDebugPositionInfo(
Mathieu Chartier31f4c9f2017-12-08 15:46:11 -0800490 accessor.DebugInfoOffset(), CollectLineNumbers, &context);
Andreas Gampeda3e5612016-12-13 19:00:53 -0800491 if (!success) {
492 return ERR(ABSENT_INFORMATION);
493 }
494
495 unsigned char* data;
496 jlong mem_size = context.size() * sizeof(jvmtiLineNumberEntry);
497 jvmtiError alloc_error = env->Allocate(mem_size, &data);
498 if (alloc_error != ERR(NONE)) {
499 return alloc_error;
500 }
501 *table_ptr = reinterpret_cast<jvmtiLineNumberEntry*>(data);
502 memcpy(*table_ptr, context.data(), mem_size);
503 *entry_count_ptr = static_cast<jint>(context.size());
504
505 return ERR(NONE);
506}
507
Andreas Gampefdeef522017-01-09 14:40:25 -0800508template <typename T>
509static jvmtiError IsMethodT(jvmtiEnv* env ATTRIBUTE_UNUSED,
510 jmethodID method,
511 T test,
512 jboolean* is_t_ptr) {
513 if (method == nullptr) {
514 return ERR(INVALID_METHODID);
515 }
516 if (is_t_ptr == nullptr) {
517 return ERR(NULL_POINTER);
518 }
519
520 art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
521 *is_t_ptr = test(art_method) ? JNI_TRUE : JNI_FALSE;
522
523 return ERR(NONE);
524}
525
526jvmtiError MethodUtil::IsMethodNative(jvmtiEnv* env, jmethodID m, jboolean* is_native_ptr) {
527 auto test = [](art::ArtMethod* method) {
528 return method->IsNative();
529 };
530 return IsMethodT(env, m, test, is_native_ptr);
531}
532
533jvmtiError MethodUtil::IsMethodObsolete(jvmtiEnv* env, jmethodID m, jboolean* is_obsolete_ptr) {
534 auto test = [](art::ArtMethod* method) {
535 return method->IsObsolete();
536 };
537 return IsMethodT(env, m, test, is_obsolete_ptr);
538}
539
540jvmtiError MethodUtil::IsMethodSynthetic(jvmtiEnv* env, jmethodID m, jboolean* is_synthetic_ptr) {
541 auto test = [](art::ArtMethod* method) {
542 return method->IsSynthetic();
543 };
544 return IsMethodT(env, m, test, is_synthetic_ptr);
545}
546
Alex Lightbebd7bd2017-07-25 14:05:52 -0700547class CommonLocalVariableClosure : public art::Closure {
548 public:
549 CommonLocalVariableClosure(art::Thread* caller,
550 jint depth,
551 jint slot)
552 : result_(ERR(INTERNAL)), caller_(caller), depth_(depth), slot_(slot) {}
553
554 void Run(art::Thread* self) OVERRIDE REQUIRES(art::Locks::mutator_lock_) {
555 art::Locks::mutator_lock_->AssertSharedHeld(art::Thread::Current());
556 std::unique_ptr<art::Context> context(art::Context::Create());
557 FindFrameAtDepthVisitor visitor(self, context.get(), depth_);
558 visitor.WalkStack();
559 if (!visitor.FoundFrame()) {
560 // Must have been a bad depth.
561 result_ = ERR(NO_MORE_FRAMES);
562 return;
563 }
564 art::ArtMethod* method = visitor.GetMethod();
Alex Light3dea2122017-10-11 15:56:48 +0000565 // Native and 'art' proxy methods don't have registers.
566 if (method->IsNative() || method->IsProxyMethod()) {
567 // TODO It might be useful to fake up support for get at least on proxy frames.
Alex Lightbebd7bd2017-07-25 14:05:52 -0700568 result_ = ERR(OPAQUE_FRAME);
569 return;
David Sehr0225f8e2018-01-31 08:52:24 +0000570 } else if (method->DexInstructionData().RegistersSize() <= slot_) {
Alex Lightbebd7bd2017-07-25 14:05:52 -0700571 result_ = ERR(INVALID_SLOT);
572 return;
573 }
Alex Light0a5ec3d2017-07-25 16:50:26 -0700574 bool needs_instrument = !visitor.IsShadowFrame();
Alex Lightbebd7bd2017-07-25 14:05:52 -0700575 uint32_t pc = visitor.GetDexPc(/*abort_on_failure*/ false);
Andreas Gampee2abbc62017-09-15 11:59:26 -0700576 if (pc == art::dex::kDexNoIndex) {
Alex Lightbebd7bd2017-07-25 14:05:52 -0700577 // Cannot figure out current PC.
578 result_ = ERR(OPAQUE_FRAME);
579 return;
580 }
581 std::string descriptor;
582 art::Primitive::Type slot_type = art::Primitive::kPrimVoid;
583 jvmtiError err = GetSlotType(method, pc, &descriptor, &slot_type);
584 if (err != OK) {
585 result_ = err;
586 return;
587 }
588
589 err = GetTypeError(method, slot_type, descriptor);
590 if (err != OK) {
591 result_ = err;
592 return;
593 }
594 result_ = Execute(method, visitor);
Alex Light0a5ec3d2017-07-25 16:50:26 -0700595 if (needs_instrument) {
596 art::Runtime::Current()->GetInstrumentation()->InstrumentThreadStack(self);
597 }
Alex Lightbebd7bd2017-07-25 14:05:52 -0700598 }
599
600 jvmtiError GetResult() const {
601 return result_;
602 }
603
604 protected:
605 virtual jvmtiError Execute(art::ArtMethod* method, art::StackVisitor& visitor)
606 REQUIRES(art::Locks::mutator_lock_) = 0;
607 virtual jvmtiError GetTypeError(art::ArtMethod* method,
608 art::Primitive::Type type,
609 const std::string& descriptor)
610 REQUIRES(art::Locks::mutator_lock_) = 0;
611
612 jvmtiError GetSlotType(art::ArtMethod* method,
613 uint32_t dex_pc,
614 /*out*/std::string* descriptor,
615 /*out*/art::Primitive::Type* type)
616 REQUIRES(art::Locks::mutator_lock_) {
617 const art::DexFile* dex_file = method->GetDexFile();
Mathieu Chartier31f4c9f2017-12-08 15:46:11 -0800618 if (dex_file == nullptr) {
619 return ERR(OPAQUE_FRAME);
620 }
David Sehr0225f8e2018-01-31 08:52:24 +0000621 art::CodeItemDebugInfoAccessor accessor(method->DexInstructionDebugInfo());
Mathieu Chartier31f4c9f2017-12-08 15:46:11 -0800622 if (!accessor.HasCodeItem()) {
Alex Lightbebd7bd2017-07-25 14:05:52 -0700623 return ERR(OPAQUE_FRAME);
624 }
625
626 struct GetLocalVariableInfoContext {
627 explicit GetLocalVariableInfoContext(jint slot,
628 uint32_t pc,
629 std::string* out_descriptor,
630 art::Primitive::Type* out_type)
631 : found_(false), jslot_(slot), pc_(pc), descriptor_(out_descriptor), type_(out_type) {
632 *descriptor_ = "";
633 *type_ = art::Primitive::kPrimVoid;
634 }
635
636 static void Callback(void* raw_ctx, const art::DexFile::LocalInfo& entry) {
637 reinterpret_cast<GetLocalVariableInfoContext*>(raw_ctx)->Handle(entry);
638 }
639
640 void Handle(const art::DexFile::LocalInfo& entry) {
641 if (found_) {
642 return;
643 } else if (entry.start_address_ <= pc_ &&
644 entry.end_address_ > pc_ &&
645 entry.reg_ == jslot_) {
646 found_ = true;
647 *type_ = art::Primitive::GetType(entry.descriptor_[0]);
648 *descriptor_ = entry.descriptor_;
649 }
650 return;
651 }
652
653 bool found_;
654 jint jslot_;
655 uint32_t pc_;
656 std::string* descriptor_;
657 art::Primitive::Type* type_;
658 };
659
660 GetLocalVariableInfoContext context(slot_, dex_pc, descriptor, type);
Mathieu Chartier31f4c9f2017-12-08 15:46:11 -0800661 if (!dex_file->DecodeDebugLocalInfo(accessor.RegistersSize(),
662 accessor.InsSize(),
663 accessor.InsnsSizeInCodeUnits(),
664 accessor.DebugInfoOffset(),
Alex Lightbebd7bd2017-07-25 14:05:52 -0700665 method->IsStatic(),
666 method->GetDexMethodIndex(),
667 GetLocalVariableInfoContext::Callback,
668 &context) || !context.found_) {
669 // Something went wrong with decoding the debug information. It might as well not be there.
670 return ERR(INVALID_SLOT);
671 } else {
672 return OK;
673 }
674 }
675
676 jvmtiError result_;
677 art::Thread* caller_;
678 jint depth_;
679 jint slot_;
680};
681
682class GetLocalVariableClosure : public CommonLocalVariableClosure {
683 public:
684 GetLocalVariableClosure(art::Thread* caller,
685 jint depth,
686 jint slot,
687 art::Primitive::Type type,
688 jvalue* val)
689 : CommonLocalVariableClosure(caller, depth, slot), type_(type), val_(val) {}
690
691 protected:
692 jvmtiError GetTypeError(art::ArtMethod* method ATTRIBUTE_UNUSED,
693 art::Primitive::Type slot_type,
694 const std::string& descriptor ATTRIBUTE_UNUSED)
695 OVERRIDE REQUIRES(art::Locks::mutator_lock_) {
696 switch (slot_type) {
697 case art::Primitive::kPrimByte:
698 case art::Primitive::kPrimChar:
699 case art::Primitive::kPrimInt:
700 case art::Primitive::kPrimShort:
701 case art::Primitive::kPrimBoolean:
702 return type_ == art::Primitive::kPrimInt ? OK : ERR(TYPE_MISMATCH);
703 case art::Primitive::kPrimLong:
704 case art::Primitive::kPrimFloat:
705 case art::Primitive::kPrimDouble:
706 case art::Primitive::kPrimNot:
707 return type_ == slot_type ? OK : ERR(TYPE_MISMATCH);
708 case art::Primitive::kPrimVoid:
709 LOG(FATAL) << "Unexpected primitive type " << slot_type;
710 UNREACHABLE();
711 }
712 }
713
714 jvmtiError Execute(art::ArtMethod* method, art::StackVisitor& visitor)
715 OVERRIDE REQUIRES(art::Locks::mutator_lock_) {
716 switch (type_) {
717 case art::Primitive::kPrimNot: {
718 uint32_t ptr_val;
719 if (!visitor.GetVReg(method,
720 static_cast<uint16_t>(slot_),
721 art::kReferenceVReg,
722 &ptr_val)) {
723 return ERR(OPAQUE_FRAME);
724 }
725 art::ObjPtr<art::mirror::Object> obj(reinterpret_cast<art::mirror::Object*>(ptr_val));
726 val_->l = obj.IsNull() ? nullptr : caller_->GetJniEnv()->AddLocalReference<jobject>(obj);
727 break;
728 }
729 case art::Primitive::kPrimInt:
730 case art::Primitive::kPrimFloat: {
731 if (!visitor.GetVReg(method,
732 static_cast<uint16_t>(slot_),
733 type_ == art::Primitive::kPrimFloat ? art::kFloatVReg : art::kIntVReg,
734 reinterpret_cast<uint32_t*>(&val_->i))) {
735 return ERR(OPAQUE_FRAME);
736 }
737 break;
738 }
739 case art::Primitive::kPrimDouble:
740 case art::Primitive::kPrimLong: {
741 auto lo_type = type_ == art::Primitive::kPrimLong ? art::kLongLoVReg : art::kDoubleLoVReg;
742 auto high_type = type_ == art::Primitive::kPrimLong ? art::kLongHiVReg : art::kDoubleHiVReg;
743 if (!visitor.GetVRegPair(method,
744 static_cast<uint16_t>(slot_),
745 lo_type,
746 high_type,
747 reinterpret_cast<uint64_t*>(&val_->j))) {
748 return ERR(OPAQUE_FRAME);
749 }
750 break;
751 }
752 default: {
753 LOG(FATAL) << "unexpected register type " << type_;
754 UNREACHABLE();
755 }
756 }
757 return OK;
758 }
759
760 private:
761 art::Primitive::Type type_;
762 jvalue* val_;
763};
764
765jvmtiError MethodUtil::GetLocalVariableGeneric(jvmtiEnv* env ATTRIBUTE_UNUSED,
766 jthread thread,
767 jint depth,
768 jint slot,
769 art::Primitive::Type type,
770 jvalue* val) {
771 if (depth < 0) {
772 return ERR(ILLEGAL_ARGUMENT);
773 }
774 art::Thread* self = art::Thread::Current();
Alex Light0a5ec3d2017-07-25 16:50:26 -0700775 // Suspend JIT since it can get confused if we deoptimize methods getting jitted.
776 art::jit::ScopedJitSuspend suspend_jit;
Alex Lightbebd7bd2017-07-25 14:05:52 -0700777 art::ScopedObjectAccess soa(self);
Alex Lightb1e31a82017-10-04 16:57:36 -0700778 art::Locks::thread_list_lock_->ExclusiveLock(self);
Alex Light7ddc23d2017-09-22 15:33:41 -0700779 art::Thread* target = nullptr;
780 jvmtiError err = ERR(INTERNAL);
781 if (!ThreadUtil::GetAliveNativeThread(thread, soa, &target, &err)) {
Alex Lightb1e31a82017-10-04 16:57:36 -0700782 art::Locks::thread_list_lock_->ExclusiveUnlock(self);
Alex Light7ddc23d2017-09-22 15:33:41 -0700783 return err;
Alex Lightbebd7bd2017-07-25 14:05:52 -0700784 }
785 GetLocalVariableClosure c(self, depth, slot, type, val);
Alex Lightb1e31a82017-10-04 16:57:36 -0700786 // RequestSynchronousCheckpoint releases the thread_list_lock_ as a part of its execution.
Alex Lightd9aff132017-10-31 22:30:05 +0000787 if (!ThreadUtil::RequestGCSafeSynchronousCheckpoint(target, &c)) {
Alex Lightbebd7bd2017-07-25 14:05:52 -0700788 return ERR(THREAD_NOT_ALIVE);
789 } else {
790 return c.GetResult();
791 }
792}
793
794class SetLocalVariableClosure : public CommonLocalVariableClosure {
795 public:
796 SetLocalVariableClosure(art::Thread* caller,
797 jint depth,
798 jint slot,
799 art::Primitive::Type type,
800 jvalue val)
801 : CommonLocalVariableClosure(caller, depth, slot), type_(type), val_(val) {}
802
803 protected:
804 jvmtiError GetTypeError(art::ArtMethod* method,
805 art::Primitive::Type slot_type,
806 const std::string& descriptor)
807 OVERRIDE REQUIRES(art::Locks::mutator_lock_) {
808 switch (slot_type) {
809 case art::Primitive::kPrimNot: {
810 if (type_ != art::Primitive::kPrimNot) {
811 return ERR(TYPE_MISMATCH);
812 } else if (val_.l == nullptr) {
813 return OK;
814 } else {
815 art::ClassLinker* cl = art::Runtime::Current()->GetClassLinker();
816 art::ObjPtr<art::mirror::Class> set_class =
817 caller_->DecodeJObject(val_.l)->GetClass();
818 art::ObjPtr<art::mirror::ClassLoader> loader =
819 method->GetDeclaringClass()->GetClassLoader();
820 art::ObjPtr<art::mirror::Class> slot_class =
821 cl->LookupClass(caller_, descriptor.c_str(), loader);
822 DCHECK(!slot_class.IsNull());
823 return slot_class->IsAssignableFrom(set_class) ? OK : ERR(TYPE_MISMATCH);
824 }
825 }
826 case art::Primitive::kPrimByte:
827 case art::Primitive::kPrimChar:
828 case art::Primitive::kPrimInt:
829 case art::Primitive::kPrimShort:
830 case art::Primitive::kPrimBoolean:
831 return type_ == art::Primitive::kPrimInt ? OK : ERR(TYPE_MISMATCH);
832 case art::Primitive::kPrimLong:
833 case art::Primitive::kPrimFloat:
834 case art::Primitive::kPrimDouble:
835 return type_ == slot_type ? OK : ERR(TYPE_MISMATCH);
836 case art::Primitive::kPrimVoid:
837 LOG(FATAL) << "Unexpected primitive type " << slot_type;
838 UNREACHABLE();
839 }
840 }
841
842 jvmtiError Execute(art::ArtMethod* method, art::StackVisitor& visitor)
843 OVERRIDE REQUIRES(art::Locks::mutator_lock_) {
844 switch (type_) {
845 case art::Primitive::kPrimNot: {
846 uint32_t ptr_val;
847 art::ObjPtr<art::mirror::Object> obj(caller_->DecodeJObject(val_.l));
848 ptr_val = static_cast<uint32_t>(reinterpret_cast<uintptr_t>(obj.Ptr()));
849 if (!visitor.SetVReg(method,
850 static_cast<uint16_t>(slot_),
851 ptr_val,
852 art::kReferenceVReg)) {
853 return ERR(OPAQUE_FRAME);
854 }
855 break;
856 }
857 case art::Primitive::kPrimInt:
858 case art::Primitive::kPrimFloat: {
859 if (!visitor.SetVReg(method,
860 static_cast<uint16_t>(slot_),
861 static_cast<uint32_t>(val_.i),
862 type_ == art::Primitive::kPrimFloat ? art::kFloatVReg
863 : art::kIntVReg)) {
864 return ERR(OPAQUE_FRAME);
865 }
866 break;
867 }
868 case art::Primitive::kPrimDouble:
869 case art::Primitive::kPrimLong: {
870 auto lo_type = type_ == art::Primitive::kPrimLong ? art::kLongLoVReg : art::kDoubleLoVReg;
871 auto high_type = type_ == art::Primitive::kPrimLong ? art::kLongHiVReg : art::kDoubleHiVReg;
872 if (!visitor.SetVRegPair(method,
873 static_cast<uint16_t>(slot_),
874 static_cast<uint64_t>(val_.j),
875 lo_type,
876 high_type)) {
877 return ERR(OPAQUE_FRAME);
878 }
879 break;
880 }
881 default: {
882 LOG(FATAL) << "unexpected register type " << type_;
883 UNREACHABLE();
884 }
885 }
886 return OK;
887 }
888
889 private:
890 art::Primitive::Type type_;
891 jvalue val_;
892};
893
894jvmtiError MethodUtil::SetLocalVariableGeneric(jvmtiEnv* env ATTRIBUTE_UNUSED,
895 jthread thread,
896 jint depth,
897 jint slot,
898 art::Primitive::Type type,
899 jvalue val) {
900 if (depth < 0) {
901 return ERR(ILLEGAL_ARGUMENT);
902 }
903 art::Thread* self = art::Thread::Current();
Alex Light0a5ec3d2017-07-25 16:50:26 -0700904 // Suspend JIT since it can get confused if we deoptimize methods getting jitted.
905 art::jit::ScopedJitSuspend suspend_jit;
Alex Lightbebd7bd2017-07-25 14:05:52 -0700906 art::ScopedObjectAccess soa(self);
Alex Lightb1e31a82017-10-04 16:57:36 -0700907 art::Locks::thread_list_lock_->ExclusiveLock(self);
Alex Light7ddc23d2017-09-22 15:33:41 -0700908 art::Thread* target = nullptr;
909 jvmtiError err = ERR(INTERNAL);
910 if (!ThreadUtil::GetAliveNativeThread(thread, soa, &target, &err)) {
Alex Lightb1e31a82017-10-04 16:57:36 -0700911 art::Locks::thread_list_lock_->ExclusiveUnlock(self);
Alex Light7ddc23d2017-09-22 15:33:41 -0700912 return err;
Alex Lightbebd7bd2017-07-25 14:05:52 -0700913 }
914 SetLocalVariableClosure c(self, depth, slot, type, val);
Alex Lightb1e31a82017-10-04 16:57:36 -0700915 // RequestSynchronousCheckpoint releases the thread_list_lock_ as a part of its execution.
Alex Lightd9aff132017-10-31 22:30:05 +0000916 if (!ThreadUtil::RequestGCSafeSynchronousCheckpoint(target, &c)) {
Alex Lightbebd7bd2017-07-25 14:05:52 -0700917 return ERR(THREAD_NOT_ALIVE);
918 } else {
919 return c.GetResult();
920 }
921}
922
923class GetLocalInstanceClosure : public art::Closure {
924 public:
925 GetLocalInstanceClosure(art::Thread* caller, jint depth, jobject* val)
926 : result_(ERR(INTERNAL)),
927 caller_(caller),
928 depth_(depth),
929 val_(val) {}
930
931 void Run(art::Thread* self) OVERRIDE REQUIRES(art::Locks::mutator_lock_) {
932 art::Locks::mutator_lock_->AssertSharedHeld(art::Thread::Current());
933 std::unique_ptr<art::Context> context(art::Context::Create());
934 FindFrameAtDepthVisitor visitor(self, context.get(), depth_);
935 visitor.WalkStack();
936 if (!visitor.FoundFrame()) {
937 // Must have been a bad depth.
938 result_ = ERR(NO_MORE_FRAMES);
939 return;
940 }
Alex Lightbebd7bd2017-07-25 14:05:52 -0700941 result_ = OK;
942 art::ObjPtr<art::mirror::Object> obj = visitor.GetThisObject();
943 *val_ = obj.IsNull() ? nullptr : caller_->GetJniEnv()->AddLocalReference<jobject>(obj);
944 }
945
946 jvmtiError GetResult() const {
947 return result_;
948 }
949
950 private:
951 jvmtiError result_;
952 art::Thread* caller_;
953 jint depth_;
954 jobject* val_;
955};
956
957jvmtiError MethodUtil::GetLocalInstance(jvmtiEnv* env ATTRIBUTE_UNUSED,
958 jthread thread,
959 jint depth,
960 jobject* data) {
961 if (depth < 0) {
962 return ERR(ILLEGAL_ARGUMENT);
963 }
964 art::Thread* self = art::Thread::Current();
965 art::ScopedObjectAccess soa(self);
Alex Lightb1e31a82017-10-04 16:57:36 -0700966 art::Locks::thread_list_lock_->ExclusiveLock(self);
Alex Light7ddc23d2017-09-22 15:33:41 -0700967 art::Thread* target = nullptr;
968 jvmtiError err = ERR(INTERNAL);
969 if (!ThreadUtil::GetAliveNativeThread(thread, soa, &target, &err)) {
Alex Lightb1e31a82017-10-04 16:57:36 -0700970 art::Locks::thread_list_lock_->ExclusiveUnlock(self);
Alex Light7ddc23d2017-09-22 15:33:41 -0700971 return err;
Alex Lightbebd7bd2017-07-25 14:05:52 -0700972 }
973 GetLocalInstanceClosure c(self, depth, data);
Alex Lightb1e31a82017-10-04 16:57:36 -0700974 // RequestSynchronousCheckpoint releases the thread_list_lock_ as a part of its execution.
Alex Lightd9aff132017-10-31 22:30:05 +0000975 if (!ThreadUtil::RequestGCSafeSynchronousCheckpoint(target, &c)) {
Alex Lightbebd7bd2017-07-25 14:05:52 -0700976 return ERR(THREAD_NOT_ALIVE);
977 } else {
978 return c.GetResult();
979 }
980}
981
982#define FOR_JVMTI_JVALUE_TYPES(fn) \
983 fn(jint, art::Primitive::kPrimInt, i) \
984 fn(jlong, art::Primitive::kPrimLong, j) \
985 fn(jfloat, art::Primitive::kPrimFloat, f) \
986 fn(jdouble, art::Primitive::kPrimDouble, d) \
987 fn(jobject, art::Primitive::kPrimNot, l)
988
989namespace impl {
990
991template<typename T> void WriteJvalue(T, jvalue*);
992template<typename T> void ReadJvalue(jvalue, T*);
993template<typename T> art::Primitive::Type GetJNIType();
994
995#define JNI_TYPE_CHAR(type, prim, id) \
996template<> art::Primitive::Type GetJNIType<type>() { \
997 return prim; \
998}
999
1000FOR_JVMTI_JVALUE_TYPES(JNI_TYPE_CHAR);
1001
1002#undef JNI_TYPE_CHAR
1003
Andreas Gampe49fc60e2017-08-24 13:19:59 -07001004#define RW_JVALUE(srctype, prim, id) \
1005 template<> void ReadJvalue<srctype>(jvalue in, std::add_pointer<srctype>::type out) { \
Alex Lightbebd7bd2017-07-25 14:05:52 -07001006 *out = in.id; \
1007 } \
Andreas Gampe49fc60e2017-08-24 13:19:59 -07001008 template<> void WriteJvalue<srctype>(srctype in, jvalue* out) { \
Alex Lightbebd7bd2017-07-25 14:05:52 -07001009 out->id = in; \
1010 }
1011
1012FOR_JVMTI_JVALUE_TYPES(RW_JVALUE);
1013
1014#undef RW_JVALUE
1015
1016} // namespace impl
1017
1018template<typename T>
1019jvmtiError MethodUtil::SetLocalVariable(jvmtiEnv* env,
1020 jthread thread,
1021 jint depth,
1022 jint slot,
1023 T data) {
1024 jvalue v = {.j = 0};
1025 art::Primitive::Type type = impl::GetJNIType<T>();
1026 impl::WriteJvalue(data, &v);
1027 return SetLocalVariableGeneric(env, thread, depth, slot, type, v);
1028}
1029
1030template<typename T>
1031jvmtiError MethodUtil::GetLocalVariable(jvmtiEnv* env,
1032 jthread thread,
1033 jint depth,
1034 jint slot,
1035 T* data) {
1036 if (data == nullptr) {
1037 return ERR(NULL_POINTER);
1038 }
1039 jvalue v = {.j = 0};
1040 art::Primitive::Type type = impl::GetJNIType<T>();
1041 jvmtiError err = GetLocalVariableGeneric(env, thread, depth, slot, type, &v);
1042 if (err != OK) {
1043 return err;
1044 } else {
1045 impl::ReadJvalue(v, data);
1046 return OK;
1047 }
1048}
1049
Andreas Gampe49fc60e2017-08-24 13:19:59 -07001050#define GET_SET_LV(srctype, prim, id) \
1051 template jvmtiError MethodUtil::GetLocalVariable<srctype>(jvmtiEnv*, \
1052 jthread, \
1053 jint, \
1054 jint, \
1055 std::add_pointer<srctype>::type); \
1056 template jvmtiError MethodUtil::SetLocalVariable<srctype>(jvmtiEnv*, \
1057 jthread, \
1058 jint, \
1059 jint, \
1060 srctype);
Alex Lightbebd7bd2017-07-25 14:05:52 -07001061
1062FOR_JVMTI_JVALUE_TYPES(GET_SET_LV);
1063
1064#undef GET_SET_LV
1065
1066#undef FOR_JVMTI_JVALUE_TYPES
1067
Andreas Gampe3c252f02016-10-27 18:25:17 -07001068} // namespace openjdkjvmti