blob: 8141f51a115ea86669cfb89643111ecc44db3b25 [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"
Andreas Gampe27dfa052017-02-16 15:04:36 -080040#include "dex_file_annotations.h"
Andreas Gampee2abbc62017-09-15 11:59:26 -070041#include "dex_file_types.h"
Alex Lightd78ddec2017-04-18 15:20:38 -070042#include "events-inl.h"
Alex Light0a5ec3d2017-07-25 16:50:26 -070043#include "jit/jit.h"
Andreas Gampe13b27842016-11-07 16:48:23 -080044#include "jni_internal.h"
Alex Lightbebd7bd2017-07-25 14:05:52 -070045#include "mirror/class-inl.h"
46#include "mirror/class_loader.h"
47#include "mirror/object-inl.h"
Andreas Gampe27dfa052017-02-16 15:04:36 -080048#include "mirror/object_array-inl.h"
Andreas Gampe36bcd4f2016-10-28 18:07:18 -070049#include "modifiers.h"
Steven Morelande431e272017-07-18 16:53:49 -070050#include "nativehelper/ScopedLocalRef.h"
Alex Lightd78ddec2017-04-18 15:20:38 -070051#include "runtime_callbacks.h"
Andreas Gampe3c252f02016-10-27 18:25:17 -070052#include "scoped_thread_state_change-inl.h"
Alex Lightbebd7bd2017-07-25 14:05:52 -070053#include "stack.h"
Andreas Gampeb486a982017-06-01 13:45:54 -070054#include "thread-current-inl.h"
Alex Lightd78ddec2017-04-18 15:20:38 -070055#include "thread_list.h"
Alex Lighte814f9d2017-07-31 16:14:39 -070056#include "ti_stack.h"
Alex Lightbebd7bd2017-07-25 14:05:52 -070057#include "ti_thread.h"
Alex Light0af8cde2017-04-20 13:35:05 -070058#include "ti_phase.h"
Andreas Gampe3c252f02016-10-27 18:25:17 -070059
60namespace openjdkjvmti {
61
Alex Lightd78ddec2017-04-18 15:20:38 -070062struct TiMethodCallback : public art::MethodCallback {
63 void RegisterNativeMethod(art::ArtMethod* method,
64 const void* cur_method,
65 /*out*/void** new_method)
66 OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) {
67 if (event_handler->IsEventEnabledAnywhere(ArtJvmtiEvent::kNativeMethodBind)) {
68 art::Thread* thread = art::Thread::Current();
Alex Light0af8cde2017-04-20 13:35:05 -070069 art::JNIEnvExt* jnienv = thread->GetJniEnv();
Alex Lightd78ddec2017-04-18 15:20:38 -070070 ScopedLocalRef<jthread> thread_jni(
Alex Light0af8cde2017-04-20 13:35:05 -070071 jnienv, PhaseUtil::IsLivePhase() ? jnienv->AddLocalReference<jthread>(thread->GetPeer())
72 : nullptr);
Alex Lightd78ddec2017-04-18 15:20:38 -070073 art::ScopedThreadSuspension sts(thread, art::ThreadState::kNative);
74 event_handler->DispatchEvent<ArtJvmtiEvent::kNativeMethodBind>(
75 thread,
Alex Light0af8cde2017-04-20 13:35:05 -070076 static_cast<JNIEnv*>(jnienv),
Alex Lightd78ddec2017-04-18 15:20:38 -070077 thread_jni.get(),
78 art::jni::EncodeArtMethod(method),
79 const_cast<void*>(cur_method),
80 new_method);
81 }
82 }
83
84 EventHandler* event_handler = nullptr;
85};
86
87TiMethodCallback gMethodCallback;
88
Alex Light21611932017-09-26 13:07:39 -070089// TODO We should make this much more selective in the future so we only return true when we
90// actually care about the method (i.e. had locals changed, have breakpoints, etc.). For now though
91// we can just assume that we care we are loaded at all.
92//
93// Even if we don't keep track of this at the method level we might want to keep track of it at the
94// level of enabled capabilities.
95struct TiMethodInspectionCallback : public art::MethodInspectionCallback {
96 bool IsMethodBeingInspected(art::ArtMethod* method ATTRIBUTE_UNUSED)
97 OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) {
98 return true;
99 }
100};
101
102TiMethodInspectionCallback gMethodInspectionCallback;
103
Alex Lightd78ddec2017-04-18 15:20:38 -0700104void MethodUtil::Register(EventHandler* handler) {
105 gMethodCallback.event_handler = handler;
106 art::ScopedThreadStateChange stsc(art::Thread::Current(),
107 art::ThreadState::kWaitingForDebuggerToAttach);
108 art::ScopedSuspendAll ssa("Add method callback");
Alex Light21611932017-09-26 13:07:39 -0700109 art::RuntimeCallbacks* callbacks = art::Runtime::Current()->GetRuntimeCallbacks();
110 callbacks->AddMethodCallback(&gMethodCallback);
111 callbacks->AddMethodInspectionCallback(&gMethodInspectionCallback);
Alex Lightd78ddec2017-04-18 15:20:38 -0700112}
113
114void MethodUtil::Unregister() {
115 art::ScopedThreadStateChange stsc(art::Thread::Current(),
116 art::ThreadState::kWaitingForDebuggerToAttach);
117 art::ScopedSuspendAll ssa("Remove method callback");
Alex Light21611932017-09-26 13:07:39 -0700118 art::RuntimeCallbacks* callbacks = art::Runtime::Current()->GetRuntimeCallbacks();
119 callbacks->RemoveMethodCallback(&gMethodCallback);
120 callbacks->AddMethodInspectionCallback(&gMethodInspectionCallback);
Alex Lightd78ddec2017-04-18 15:20:38 -0700121}
122
Alex Light4c174282017-07-05 10:18:18 -0700123jvmtiError MethodUtil::GetBytecodes(jvmtiEnv* env,
124 jmethodID method,
125 jint* size_ptr,
126 unsigned char** bytecode_ptr) {
127 if (method == nullptr) {
128 return ERR(INVALID_METHODID);
129 }
130 art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
131
132 if (art_method->IsNative()) {
133 return ERR(NATIVE_METHOD);
134 }
135
136 if (size_ptr == nullptr || bytecode_ptr == nullptr) {
137 return ERR(NULL_POINTER);
138 }
139
140 art::ScopedObjectAccess soa(art::Thread::Current());
141 const art::DexFile::CodeItem* code_item = art_method->GetCodeItem();
142 if (code_item == nullptr) {
143 *size_ptr = 0;
144 *bytecode_ptr = nullptr;
145 return OK;
146 }
147 // 2 bytes per instruction for dex code.
148 *size_ptr = code_item->insns_size_in_code_units_ * 2;
149 jvmtiError err = env->Allocate(*size_ptr, bytecode_ptr);
150 if (err != OK) {
151 return err;
152 }
153 memcpy(*bytecode_ptr, code_item->insns_, *size_ptr);
154 return OK;
155}
156
Andreas Gampef71832e2017-01-09 11:38:04 -0800157jvmtiError MethodUtil::GetArgumentsSize(jvmtiEnv* env ATTRIBUTE_UNUSED,
158 jmethodID method,
159 jint* size_ptr) {
160 if (method == nullptr) {
161 return ERR(INVALID_METHODID);
162 }
163 art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
164
165 if (art_method->IsNative()) {
166 return ERR(NATIVE_METHOD);
167 }
168
169 if (size_ptr == nullptr) {
170 return ERR(NULL_POINTER);
171 }
172
173 art::ScopedObjectAccess soa(art::Thread::Current());
174 if (art_method->IsProxyMethod() || art_method->IsAbstract()) {
Andreas Gampee1f79b62017-04-12 21:11:28 -0700175 // Use the shorty.
176 art::ArtMethod* base_method = art_method->GetInterfaceMethodIfProxy(art::kRuntimePointerSize);
177 size_t arg_count = art::ArtMethod::NumArgRegisters(base_method->GetShorty());
178 if (!base_method->IsStatic()) {
179 arg_count++;
180 }
181 *size_ptr = static_cast<jint>(arg_count);
Andreas Gampef71832e2017-01-09 11:38:04 -0800182 return ERR(NONE);
183 }
184
185 DCHECK_NE(art_method->GetCodeItemOffset(), 0u);
186 *size_ptr = art_method->GetCodeItem()->ins_size_;
187
188 return ERR(NONE);
189}
190
Alex Lightce68cc62017-07-26 10:30:38 -0700191jvmtiError MethodUtil::GetLocalVariableTable(jvmtiEnv* env,
192 jmethodID method,
193 jint* entry_count_ptr,
194 jvmtiLocalVariableEntry** table_ptr) {
195 if (method == nullptr) {
196 return ERR(INVALID_METHODID);
197 }
198 art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
199
200 if (art_method->IsNative()) {
201 return ERR(NATIVE_METHOD);
202 }
203
204 if (entry_count_ptr == nullptr || table_ptr == nullptr) {
205 return ERR(NULL_POINTER);
206 }
207
208 art::ScopedObjectAccess soa(art::Thread::Current());
209 const art::DexFile* dex_file = art_method->GetDexFile();
210 const art::DexFile::CodeItem* code_item = art_method->GetCodeItem();
211 // TODO code_item == nullptr means that the method is abstract (or native, but we check that
212 // earlier). We should check what is returned by the RI in this situation since it's not clear
213 // what the appropriate return value is from the spec.
214 if (dex_file == nullptr || code_item == nullptr) {
215 return ERR(ABSENT_INFORMATION);
216 }
217
218 struct LocalVariableContext {
219 explicit LocalVariableContext(jvmtiEnv* jenv) : env_(jenv), variables_(), err_(OK) {}
220
221 static void Callback(void* raw_ctx, const art::DexFile::LocalInfo& entry) {
222 reinterpret_cast<LocalVariableContext*>(raw_ctx)->Insert(entry);
223 }
224
225 void Insert(const art::DexFile::LocalInfo& entry) {
226 if (err_ != OK) {
227 return;
228 }
229 JvmtiUniquePtr<char[]> name_str = CopyString(env_, entry.name_, &err_);
230 if (err_ != OK) {
231 return;
232 }
233 JvmtiUniquePtr<char[]> sig_str = CopyString(env_, entry.descriptor_, &err_);
234 if (err_ != OK) {
235 return;
236 }
237 JvmtiUniquePtr<char[]> generic_sig_str = CopyString(env_, entry.signature_, &err_);
238 if (err_ != OK) {
239 return;
240 }
241 variables_.push_back({
242 .start_location = static_cast<jlocation>(entry.start_address_),
243 .length = static_cast<jint>(entry.end_address_ - entry.start_address_),
244 .name = name_str.release(),
245 .signature = sig_str.release(),
246 .generic_signature = generic_sig_str.release(),
247 .slot = entry.reg_,
248 });
249 }
250
251 jvmtiError Release(jint* out_entry_count_ptr, jvmtiLocalVariableEntry** out_table_ptr) {
252 jlong table_size = sizeof(jvmtiLocalVariableEntry) * variables_.size();
253 if (err_ != OK ||
254 (err_ = env_->Allocate(table_size,
255 reinterpret_cast<unsigned char**>(out_table_ptr))) != OK) {
256 Cleanup();
257 return err_;
258 } else {
259 *out_entry_count_ptr = variables_.size();
260 memcpy(*out_table_ptr, variables_.data(), table_size);
261 return OK;
262 }
263 }
264
265 void Cleanup() {
266 for (jvmtiLocalVariableEntry& e : variables_) {
267 env_->Deallocate(reinterpret_cast<unsigned char*>(e.name));
268 env_->Deallocate(reinterpret_cast<unsigned char*>(e.signature));
269 env_->Deallocate(reinterpret_cast<unsigned char*>(e.generic_signature));
270 }
271 }
272
273 jvmtiEnv* env_;
274 std::vector<jvmtiLocalVariableEntry> variables_;
275 jvmtiError err_;
276 };
277
278 LocalVariableContext context(env);
279 if (!dex_file->DecodeDebugLocalInfo(code_item,
280 art_method->IsStatic(),
281 art_method->GetDexMethodIndex(),
282 LocalVariableContext::Callback,
283 &context)) {
284 // Something went wrong with decoding the debug information. It might as well not be there.
285 return ERR(ABSENT_INFORMATION);
286 } else {
287 return context.Release(entry_count_ptr, table_ptr);
288 }
289}
290
Andreas Gampef71832e2017-01-09 11:38:04 -0800291jvmtiError MethodUtil::GetMaxLocals(jvmtiEnv* env ATTRIBUTE_UNUSED,
292 jmethodID method,
293 jint* max_ptr) {
294 if (method == nullptr) {
295 return ERR(INVALID_METHODID);
296 }
297 art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
298
299 if (art_method->IsNative()) {
300 return ERR(NATIVE_METHOD);
301 }
302
303 if (max_ptr == nullptr) {
304 return ERR(NULL_POINTER);
305 }
306
307 art::ScopedObjectAccess soa(art::Thread::Current());
308 if (art_method->IsProxyMethod() || art_method->IsAbstract()) {
309 // This isn't specified as an error case, so return 0.
310 *max_ptr = 0;
311 return ERR(NONE);
312 }
313
314 DCHECK_NE(art_method->GetCodeItemOffset(), 0u);
315 *max_ptr = art_method->GetCodeItem()->registers_size_;
316
317 return ERR(NONE);
318}
319
Andreas Gampe3c252f02016-10-27 18:25:17 -0700320jvmtiError MethodUtil::GetMethodName(jvmtiEnv* env,
321 jmethodID method,
322 char** name_ptr,
323 char** signature_ptr,
324 char** generic_ptr) {
325 art::ScopedObjectAccess soa(art::Thread::Current());
Andreas Gampe13b27842016-11-07 16:48:23 -0800326 art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
Andreas Gampe3c252f02016-10-27 18:25:17 -0700327 art_method = art_method->GetInterfaceMethodIfProxy(art::kRuntimePointerSize);
328
Andreas Gampe54711412017-02-21 12:41:43 -0800329 JvmtiUniquePtr<char[]> name_copy;
Andreas Gampe3c252f02016-10-27 18:25:17 -0700330 if (name_ptr != nullptr) {
331 const char* method_name = art_method->GetName();
332 if (method_name == nullptr) {
333 method_name = "<error>";
334 }
Andreas Gampe54711412017-02-21 12:41:43 -0800335 jvmtiError ret;
336 name_copy = CopyString(env, method_name, &ret);
337 if (name_copy == nullptr) {
Andreas Gampe3c252f02016-10-27 18:25:17 -0700338 return ret;
339 }
Andreas Gampe54711412017-02-21 12:41:43 -0800340 *name_ptr = name_copy.get();
Andreas Gampe3c252f02016-10-27 18:25:17 -0700341 }
342
Andreas Gampe54711412017-02-21 12:41:43 -0800343 JvmtiUniquePtr<char[]> signature_copy;
Andreas Gampe3c252f02016-10-27 18:25:17 -0700344 if (signature_ptr != nullptr) {
345 const art::Signature sig = art_method->GetSignature();
346 std::string str = sig.ToString();
Andreas Gampe54711412017-02-21 12:41:43 -0800347 jvmtiError ret;
348 signature_copy = CopyString(env, str.c_str(), &ret);
349 if (signature_copy == nullptr) {
Andreas Gampe3c252f02016-10-27 18:25:17 -0700350 return ret;
351 }
Andreas Gampe54711412017-02-21 12:41:43 -0800352 *signature_ptr = signature_copy.get();
Andreas Gampe3c252f02016-10-27 18:25:17 -0700353 }
354
Andreas Gampe862bdd82016-11-18 13:31:13 -0800355 if (generic_ptr != nullptr) {
356 *generic_ptr = nullptr;
Andreas Gampe27dfa052017-02-16 15:04:36 -0800357 if (!art_method->GetDeclaringClass()->IsProxyClass()) {
358 art::mirror::ObjectArray<art::mirror::String>* str_array =
359 art::annotations::GetSignatureAnnotationForMethod(art_method);
360 if (str_array != nullptr) {
361 std::ostringstream oss;
362 for (int32_t i = 0; i != str_array->GetLength(); ++i) {
363 oss << str_array->Get(i)->ToModifiedUtf8();
364 }
365 std::string output_string = oss.str();
Andreas Gampe54711412017-02-21 12:41:43 -0800366 jvmtiError ret;
367 JvmtiUniquePtr<char[]> generic_copy = CopyString(env, output_string.c_str(), &ret);
368 if (generic_copy == nullptr) {
Andreas Gampe27dfa052017-02-16 15:04:36 -0800369 return ret;
370 }
Andreas Gampe54711412017-02-21 12:41:43 -0800371 *generic_ptr = generic_copy.release();
Andreas Gampe27dfa052017-02-16 15:04:36 -0800372 } else if (soa.Self()->IsExceptionPending()) {
373 // TODO: Should we report an error here?
374 soa.Self()->ClearException();
375 }
376 }
Andreas Gampe862bdd82016-11-18 13:31:13 -0800377 }
Andreas Gampe3c252f02016-10-27 18:25:17 -0700378
379 // Everything is fine, release the buffers.
380 name_copy.release();
381 signature_copy.release();
382
383 return ERR(NONE);
384}
385
Andreas Gampe368a2082016-10-28 17:33:13 -0700386jvmtiError MethodUtil::GetMethodDeclaringClass(jvmtiEnv* env ATTRIBUTE_UNUSED,
387 jmethodID method,
388 jclass* declaring_class_ptr) {
389 if (declaring_class_ptr == nullptr) {
390 return ERR(NULL_POINTER);
391 }
392
Andreas Gampe13b27842016-11-07 16:48:23 -0800393 art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
Andreas Gampe368a2082016-10-28 17:33:13 -0700394 // Note: No GetInterfaceMethodIfProxy, we want to actual class.
395
Andreas Gampe13b27842016-11-07 16:48:23 -0800396 art::ScopedObjectAccess soa(art::Thread::Current());
Andreas Gampe368a2082016-10-28 17:33:13 -0700397 art::mirror::Class* klass = art_method->GetDeclaringClass();
398 *declaring_class_ptr = soa.AddLocalReference<jclass>(klass);
399
400 return ERR(NONE);
401}
402
Andreas Gampef71832e2017-01-09 11:38:04 -0800403jvmtiError MethodUtil::GetMethodLocation(jvmtiEnv* env ATTRIBUTE_UNUSED,
404 jmethodID method,
405 jlocation* start_location_ptr,
406 jlocation* end_location_ptr) {
407 if (method == nullptr) {
408 return ERR(INVALID_METHODID);
409 }
410 art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
411
412 if (art_method->IsNative()) {
413 return ERR(NATIVE_METHOD);
414 }
415
416 if (start_location_ptr == nullptr || end_location_ptr == nullptr) {
417 return ERR(NULL_POINTER);
418 }
419
420 art::ScopedObjectAccess soa(art::Thread::Current());
421 if (art_method->IsProxyMethod() || art_method->IsAbstract()) {
Andreas Gampee1f79b62017-04-12 21:11:28 -0700422 // This isn't specified as an error case, so return -1/-1 as the RI does.
423 *start_location_ptr = -1;
424 *end_location_ptr = -1;
Andreas Gampef71832e2017-01-09 11:38:04 -0800425 return ERR(NONE);
426 }
427
428 DCHECK_NE(art_method->GetCodeItemOffset(), 0u);
429 *start_location_ptr = 0;
430 *end_location_ptr = art_method->GetCodeItem()->insns_size_in_code_units_ - 1;
431
432 return ERR(NONE);
433}
434
Andreas Gampe36bcd4f2016-10-28 18:07:18 -0700435jvmtiError MethodUtil::GetMethodModifiers(jvmtiEnv* env ATTRIBUTE_UNUSED,
436 jmethodID method,
437 jint* modifiers_ptr) {
438 if (modifiers_ptr == nullptr) {
439 return ERR(NULL_POINTER);
440 }
441
Andreas Gampe13b27842016-11-07 16:48:23 -0800442 art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
Andreas Gampe36bcd4f2016-10-28 18:07:18 -0700443 uint32_t modifiers = art_method->GetAccessFlags();
444
445 // Note: Keep this code in sync with Executable.fixMethodFlags.
446 if ((modifiers & art::kAccAbstract) != 0) {
447 modifiers &= ~art::kAccNative;
448 }
449 modifiers &= ~art::kAccSynchronized;
450 if ((modifiers & art::kAccDeclaredSynchronized) != 0) {
451 modifiers |= art::kAccSynchronized;
452 }
453 modifiers &= art::kAccJavaFlagsMask;
454
455 *modifiers_ptr = modifiers;
456 return ERR(NONE);
457}
458
Andreas Gampeda3e5612016-12-13 19:00:53 -0800459using LineNumberContext = std::vector<jvmtiLineNumberEntry>;
460
461static bool CollectLineNumbers(void* void_context, const art::DexFile::PositionInfo& entry) {
462 LineNumberContext* context = reinterpret_cast<LineNumberContext*>(void_context);
463 jvmtiLineNumberEntry jvmti_entry = { static_cast<jlocation>(entry.address_),
464 static_cast<jint>(entry.line_) };
465 context->push_back(jvmti_entry);
466 return false; // Collect all, no early exit.
467}
468
469jvmtiError MethodUtil::GetLineNumberTable(jvmtiEnv* env,
470 jmethodID method,
471 jint* entry_count_ptr,
472 jvmtiLineNumberEntry** table_ptr) {
473 if (method == nullptr) {
474 return ERR(NULL_POINTER);
475 }
476 art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
477 DCHECK(!art_method->IsRuntimeMethod());
478
479 const art::DexFile::CodeItem* code_item;
480 const art::DexFile* dex_file;
481 {
482 art::ScopedObjectAccess soa(art::Thread::Current());
483
484 if (art_method->IsProxyMethod()) {
485 return ERR(ABSENT_INFORMATION);
486 }
487 if (art_method->IsNative()) {
488 return ERR(NATIVE_METHOD);
489 }
490 if (entry_count_ptr == nullptr || table_ptr == nullptr) {
491 return ERR(NULL_POINTER);
492 }
493
494 code_item = art_method->GetCodeItem();
495 dex_file = art_method->GetDexFile();
496 DCHECK(code_item != nullptr) << art_method->PrettyMethod() << " " << dex_file->GetLocation();
497 }
498
499 LineNumberContext context;
500 bool success = dex_file->DecodeDebugPositionInfo(code_item, CollectLineNumbers, &context);
501 if (!success) {
502 return ERR(ABSENT_INFORMATION);
503 }
504
505 unsigned char* data;
506 jlong mem_size = context.size() * sizeof(jvmtiLineNumberEntry);
507 jvmtiError alloc_error = env->Allocate(mem_size, &data);
508 if (alloc_error != ERR(NONE)) {
509 return alloc_error;
510 }
511 *table_ptr = reinterpret_cast<jvmtiLineNumberEntry*>(data);
512 memcpy(*table_ptr, context.data(), mem_size);
513 *entry_count_ptr = static_cast<jint>(context.size());
514
515 return ERR(NONE);
516}
517
Andreas Gampefdeef522017-01-09 14:40:25 -0800518template <typename T>
519static jvmtiError IsMethodT(jvmtiEnv* env ATTRIBUTE_UNUSED,
520 jmethodID method,
521 T test,
522 jboolean* is_t_ptr) {
523 if (method == nullptr) {
524 return ERR(INVALID_METHODID);
525 }
526 if (is_t_ptr == nullptr) {
527 return ERR(NULL_POINTER);
528 }
529
530 art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
531 *is_t_ptr = test(art_method) ? JNI_TRUE : JNI_FALSE;
532
533 return ERR(NONE);
534}
535
536jvmtiError MethodUtil::IsMethodNative(jvmtiEnv* env, jmethodID m, jboolean* is_native_ptr) {
537 auto test = [](art::ArtMethod* method) {
538 return method->IsNative();
539 };
540 return IsMethodT(env, m, test, is_native_ptr);
541}
542
543jvmtiError MethodUtil::IsMethodObsolete(jvmtiEnv* env, jmethodID m, jboolean* is_obsolete_ptr) {
544 auto test = [](art::ArtMethod* method) {
545 return method->IsObsolete();
546 };
547 return IsMethodT(env, m, test, is_obsolete_ptr);
548}
549
550jvmtiError MethodUtil::IsMethodSynthetic(jvmtiEnv* env, jmethodID m, jboolean* is_synthetic_ptr) {
551 auto test = [](art::ArtMethod* method) {
552 return method->IsSynthetic();
553 };
554 return IsMethodT(env, m, test, is_synthetic_ptr);
555}
556
Alex Lightbebd7bd2017-07-25 14:05:52 -0700557class CommonLocalVariableClosure : public art::Closure {
558 public:
559 CommonLocalVariableClosure(art::Thread* caller,
560 jint depth,
561 jint slot)
562 : result_(ERR(INTERNAL)), caller_(caller), depth_(depth), slot_(slot) {}
563
564 void Run(art::Thread* self) OVERRIDE REQUIRES(art::Locks::mutator_lock_) {
565 art::Locks::mutator_lock_->AssertSharedHeld(art::Thread::Current());
566 std::unique_ptr<art::Context> context(art::Context::Create());
567 FindFrameAtDepthVisitor visitor(self, context.get(), depth_);
568 visitor.WalkStack();
569 if (!visitor.FoundFrame()) {
570 // Must have been a bad depth.
571 result_ = ERR(NO_MORE_FRAMES);
572 return;
573 }
574 art::ArtMethod* method = visitor.GetMethod();
Alex Light0a5ec3d2017-07-25 16:50:26 -0700575 if (method->IsNative()) {
Alex Lightbebd7bd2017-07-25 14:05:52 -0700576 // TODO We really should support get/set for non-shadow frames.
577 result_ = ERR(OPAQUE_FRAME);
578 return;
579 } else if (method->GetCodeItem()->registers_size_ <= slot_) {
580 result_ = ERR(INVALID_SLOT);
581 return;
582 }
Alex Light0a5ec3d2017-07-25 16:50:26 -0700583 bool needs_instrument = !visitor.IsShadowFrame();
Alex Lightbebd7bd2017-07-25 14:05:52 -0700584 uint32_t pc = visitor.GetDexPc(/*abort_on_failure*/ false);
Andreas Gampee2abbc62017-09-15 11:59:26 -0700585 if (pc == art::dex::kDexNoIndex) {
Alex Lightbebd7bd2017-07-25 14:05:52 -0700586 // Cannot figure out current PC.
587 result_ = ERR(OPAQUE_FRAME);
588 return;
589 }
590 std::string descriptor;
591 art::Primitive::Type slot_type = art::Primitive::kPrimVoid;
592 jvmtiError err = GetSlotType(method, pc, &descriptor, &slot_type);
593 if (err != OK) {
594 result_ = err;
595 return;
596 }
597
598 err = GetTypeError(method, slot_type, descriptor);
599 if (err != OK) {
600 result_ = err;
601 return;
602 }
603 result_ = Execute(method, visitor);
Alex Light0a5ec3d2017-07-25 16:50:26 -0700604 if (needs_instrument) {
605 art::Runtime::Current()->GetInstrumentation()->InstrumentThreadStack(self);
606 }
Alex Lightbebd7bd2017-07-25 14:05:52 -0700607 }
608
609 jvmtiError GetResult() const {
610 return result_;
611 }
612
613 protected:
614 virtual jvmtiError Execute(art::ArtMethod* method, art::StackVisitor& visitor)
615 REQUIRES(art::Locks::mutator_lock_) = 0;
616 virtual jvmtiError GetTypeError(art::ArtMethod* method,
617 art::Primitive::Type type,
618 const std::string& descriptor)
619 REQUIRES(art::Locks::mutator_lock_) = 0;
620
621 jvmtiError GetSlotType(art::ArtMethod* method,
622 uint32_t dex_pc,
623 /*out*/std::string* descriptor,
624 /*out*/art::Primitive::Type* type)
625 REQUIRES(art::Locks::mutator_lock_) {
626 const art::DexFile* dex_file = method->GetDexFile();
627 const art::DexFile::CodeItem* code_item = method->GetCodeItem();
628 if (dex_file == nullptr || code_item == nullptr) {
629 return ERR(OPAQUE_FRAME);
630 }
631
632 struct GetLocalVariableInfoContext {
633 explicit GetLocalVariableInfoContext(jint slot,
634 uint32_t pc,
635 std::string* out_descriptor,
636 art::Primitive::Type* out_type)
637 : found_(false), jslot_(slot), pc_(pc), descriptor_(out_descriptor), type_(out_type) {
638 *descriptor_ = "";
639 *type_ = art::Primitive::kPrimVoid;
640 }
641
642 static void Callback(void* raw_ctx, const art::DexFile::LocalInfo& entry) {
643 reinterpret_cast<GetLocalVariableInfoContext*>(raw_ctx)->Handle(entry);
644 }
645
646 void Handle(const art::DexFile::LocalInfo& entry) {
647 if (found_) {
648 return;
649 } else if (entry.start_address_ <= pc_ &&
650 entry.end_address_ > pc_ &&
651 entry.reg_ == jslot_) {
652 found_ = true;
653 *type_ = art::Primitive::GetType(entry.descriptor_[0]);
654 *descriptor_ = entry.descriptor_;
655 }
656 return;
657 }
658
659 bool found_;
660 jint jslot_;
661 uint32_t pc_;
662 std::string* descriptor_;
663 art::Primitive::Type* type_;
664 };
665
666 GetLocalVariableInfoContext context(slot_, dex_pc, descriptor, type);
667 if (!dex_file->DecodeDebugLocalInfo(code_item,
668 method->IsStatic(),
669 method->GetDexMethodIndex(),
670 GetLocalVariableInfoContext::Callback,
671 &context) || !context.found_) {
672 // Something went wrong with decoding the debug information. It might as well not be there.
673 return ERR(INVALID_SLOT);
674 } else {
675 return OK;
676 }
677 }
678
679 jvmtiError result_;
680 art::Thread* caller_;
681 jint depth_;
682 jint slot_;
683};
684
685class GetLocalVariableClosure : public CommonLocalVariableClosure {
686 public:
687 GetLocalVariableClosure(art::Thread* caller,
688 jint depth,
689 jint slot,
690 art::Primitive::Type type,
691 jvalue* val)
692 : CommonLocalVariableClosure(caller, depth, slot), type_(type), val_(val) {}
693
694 protected:
695 jvmtiError GetTypeError(art::ArtMethod* method ATTRIBUTE_UNUSED,
696 art::Primitive::Type slot_type,
697 const std::string& descriptor ATTRIBUTE_UNUSED)
698 OVERRIDE REQUIRES(art::Locks::mutator_lock_) {
699 switch (slot_type) {
700 case art::Primitive::kPrimByte:
701 case art::Primitive::kPrimChar:
702 case art::Primitive::kPrimInt:
703 case art::Primitive::kPrimShort:
704 case art::Primitive::kPrimBoolean:
705 return type_ == art::Primitive::kPrimInt ? OK : ERR(TYPE_MISMATCH);
706 case art::Primitive::kPrimLong:
707 case art::Primitive::kPrimFloat:
708 case art::Primitive::kPrimDouble:
709 case art::Primitive::kPrimNot:
710 return type_ == slot_type ? OK : ERR(TYPE_MISMATCH);
711 case art::Primitive::kPrimVoid:
712 LOG(FATAL) << "Unexpected primitive type " << slot_type;
713 UNREACHABLE();
714 }
715 }
716
717 jvmtiError Execute(art::ArtMethod* method, art::StackVisitor& visitor)
718 OVERRIDE REQUIRES(art::Locks::mutator_lock_) {
719 switch (type_) {
720 case art::Primitive::kPrimNot: {
721 uint32_t ptr_val;
722 if (!visitor.GetVReg(method,
723 static_cast<uint16_t>(slot_),
724 art::kReferenceVReg,
725 &ptr_val)) {
726 return ERR(OPAQUE_FRAME);
727 }
728 art::ObjPtr<art::mirror::Object> obj(reinterpret_cast<art::mirror::Object*>(ptr_val));
729 val_->l = obj.IsNull() ? nullptr : caller_->GetJniEnv()->AddLocalReference<jobject>(obj);
730 break;
731 }
732 case art::Primitive::kPrimInt:
733 case art::Primitive::kPrimFloat: {
734 if (!visitor.GetVReg(method,
735 static_cast<uint16_t>(slot_),
736 type_ == art::Primitive::kPrimFloat ? art::kFloatVReg : art::kIntVReg,
737 reinterpret_cast<uint32_t*>(&val_->i))) {
738 return ERR(OPAQUE_FRAME);
739 }
740 break;
741 }
742 case art::Primitive::kPrimDouble:
743 case art::Primitive::kPrimLong: {
744 auto lo_type = type_ == art::Primitive::kPrimLong ? art::kLongLoVReg : art::kDoubleLoVReg;
745 auto high_type = type_ == art::Primitive::kPrimLong ? art::kLongHiVReg : art::kDoubleHiVReg;
746 if (!visitor.GetVRegPair(method,
747 static_cast<uint16_t>(slot_),
748 lo_type,
749 high_type,
750 reinterpret_cast<uint64_t*>(&val_->j))) {
751 return ERR(OPAQUE_FRAME);
752 }
753 break;
754 }
755 default: {
756 LOG(FATAL) << "unexpected register type " << type_;
757 UNREACHABLE();
758 }
759 }
760 return OK;
761 }
762
763 private:
764 art::Primitive::Type type_;
765 jvalue* val_;
766};
767
768jvmtiError MethodUtil::GetLocalVariableGeneric(jvmtiEnv* env ATTRIBUTE_UNUSED,
769 jthread thread,
770 jint depth,
771 jint slot,
772 art::Primitive::Type type,
773 jvalue* val) {
774 if (depth < 0) {
775 return ERR(ILLEGAL_ARGUMENT);
776 }
777 art::Thread* self = art::Thread::Current();
Alex Light0a5ec3d2017-07-25 16:50:26 -0700778 // Suspend JIT since it can get confused if we deoptimize methods getting jitted.
779 art::jit::ScopedJitSuspend suspend_jit;
Alex Lightbebd7bd2017-07-25 14:05:52 -0700780 art::ScopedObjectAccess soa(self);
Alex Lightb1e31a82017-10-04 16:57:36 -0700781 art::Locks::thread_list_lock_->ExclusiveLock(self);
Alex Light7ddc23d2017-09-22 15:33:41 -0700782 art::Thread* target = nullptr;
783 jvmtiError err = ERR(INTERNAL);
784 if (!ThreadUtil::GetAliveNativeThread(thread, soa, &target, &err)) {
Alex Lightb1e31a82017-10-04 16:57:36 -0700785 art::Locks::thread_list_lock_->ExclusiveUnlock(self);
Alex Light7ddc23d2017-09-22 15:33:41 -0700786 return err;
Alex Lightbebd7bd2017-07-25 14:05:52 -0700787 }
788 GetLocalVariableClosure c(self, depth, slot, type, val);
Alex Lightb1e31a82017-10-04 16:57:36 -0700789 // RequestSynchronousCheckpoint releases the thread_list_lock_ as a part of its execution.
Alex Lightbebd7bd2017-07-25 14:05:52 -0700790 if (!target->RequestSynchronousCheckpoint(&c)) {
791 return ERR(THREAD_NOT_ALIVE);
792 } else {
793 return c.GetResult();
794 }
795}
796
797class SetLocalVariableClosure : public CommonLocalVariableClosure {
798 public:
799 SetLocalVariableClosure(art::Thread* caller,
800 jint depth,
801 jint slot,
802 art::Primitive::Type type,
803 jvalue val)
804 : CommonLocalVariableClosure(caller, depth, slot), type_(type), val_(val) {}
805
806 protected:
807 jvmtiError GetTypeError(art::ArtMethod* method,
808 art::Primitive::Type slot_type,
809 const std::string& descriptor)
810 OVERRIDE REQUIRES(art::Locks::mutator_lock_) {
811 switch (slot_type) {
812 case art::Primitive::kPrimNot: {
813 if (type_ != art::Primitive::kPrimNot) {
814 return ERR(TYPE_MISMATCH);
815 } else if (val_.l == nullptr) {
816 return OK;
817 } else {
818 art::ClassLinker* cl = art::Runtime::Current()->GetClassLinker();
819 art::ObjPtr<art::mirror::Class> set_class =
820 caller_->DecodeJObject(val_.l)->GetClass();
821 art::ObjPtr<art::mirror::ClassLoader> loader =
822 method->GetDeclaringClass()->GetClassLoader();
823 art::ObjPtr<art::mirror::Class> slot_class =
824 cl->LookupClass(caller_, descriptor.c_str(), loader);
825 DCHECK(!slot_class.IsNull());
826 return slot_class->IsAssignableFrom(set_class) ? OK : ERR(TYPE_MISMATCH);
827 }
828 }
829 case art::Primitive::kPrimByte:
830 case art::Primitive::kPrimChar:
831 case art::Primitive::kPrimInt:
832 case art::Primitive::kPrimShort:
833 case art::Primitive::kPrimBoolean:
834 return type_ == art::Primitive::kPrimInt ? OK : ERR(TYPE_MISMATCH);
835 case art::Primitive::kPrimLong:
836 case art::Primitive::kPrimFloat:
837 case art::Primitive::kPrimDouble:
838 return type_ == slot_type ? OK : ERR(TYPE_MISMATCH);
839 case art::Primitive::kPrimVoid:
840 LOG(FATAL) << "Unexpected primitive type " << slot_type;
841 UNREACHABLE();
842 }
843 }
844
845 jvmtiError Execute(art::ArtMethod* method, art::StackVisitor& visitor)
846 OVERRIDE REQUIRES(art::Locks::mutator_lock_) {
847 switch (type_) {
848 case art::Primitive::kPrimNot: {
849 uint32_t ptr_val;
850 art::ObjPtr<art::mirror::Object> obj(caller_->DecodeJObject(val_.l));
851 ptr_val = static_cast<uint32_t>(reinterpret_cast<uintptr_t>(obj.Ptr()));
852 if (!visitor.SetVReg(method,
853 static_cast<uint16_t>(slot_),
854 ptr_val,
855 art::kReferenceVReg)) {
856 return ERR(OPAQUE_FRAME);
857 }
858 break;
859 }
860 case art::Primitive::kPrimInt:
861 case art::Primitive::kPrimFloat: {
862 if (!visitor.SetVReg(method,
863 static_cast<uint16_t>(slot_),
864 static_cast<uint32_t>(val_.i),
865 type_ == art::Primitive::kPrimFloat ? art::kFloatVReg
866 : art::kIntVReg)) {
867 return ERR(OPAQUE_FRAME);
868 }
869 break;
870 }
871 case art::Primitive::kPrimDouble:
872 case art::Primitive::kPrimLong: {
873 auto lo_type = type_ == art::Primitive::kPrimLong ? art::kLongLoVReg : art::kDoubleLoVReg;
874 auto high_type = type_ == art::Primitive::kPrimLong ? art::kLongHiVReg : art::kDoubleHiVReg;
875 if (!visitor.SetVRegPair(method,
876 static_cast<uint16_t>(slot_),
877 static_cast<uint64_t>(val_.j),
878 lo_type,
879 high_type)) {
880 return ERR(OPAQUE_FRAME);
881 }
882 break;
883 }
884 default: {
885 LOG(FATAL) << "unexpected register type " << type_;
886 UNREACHABLE();
887 }
888 }
889 return OK;
890 }
891
892 private:
893 art::Primitive::Type type_;
894 jvalue val_;
895};
896
897jvmtiError MethodUtil::SetLocalVariableGeneric(jvmtiEnv* env ATTRIBUTE_UNUSED,
898 jthread thread,
899 jint depth,
900 jint slot,
901 art::Primitive::Type type,
902 jvalue val) {
903 if (depth < 0) {
904 return ERR(ILLEGAL_ARGUMENT);
905 }
906 art::Thread* self = art::Thread::Current();
Alex Light0a5ec3d2017-07-25 16:50:26 -0700907 // Suspend JIT since it can get confused if we deoptimize methods getting jitted.
908 art::jit::ScopedJitSuspend suspend_jit;
Alex Lightbebd7bd2017-07-25 14:05:52 -0700909 art::ScopedObjectAccess soa(self);
Alex Lightb1e31a82017-10-04 16:57:36 -0700910 art::Locks::thread_list_lock_->ExclusiveLock(self);
Alex Light7ddc23d2017-09-22 15:33:41 -0700911 art::Thread* target = nullptr;
912 jvmtiError err = ERR(INTERNAL);
913 if (!ThreadUtil::GetAliveNativeThread(thread, soa, &target, &err)) {
Alex Lightb1e31a82017-10-04 16:57:36 -0700914 art::Locks::thread_list_lock_->ExclusiveUnlock(self);
Alex Light7ddc23d2017-09-22 15:33:41 -0700915 return err;
Alex Lightbebd7bd2017-07-25 14:05:52 -0700916 }
917 SetLocalVariableClosure c(self, depth, slot, type, val);
Alex Lightb1e31a82017-10-04 16:57:36 -0700918 // RequestSynchronousCheckpoint releases the thread_list_lock_ as a part of its execution.
Alex Lightbebd7bd2017-07-25 14:05:52 -0700919 if (!target->RequestSynchronousCheckpoint(&c)) {
920 return ERR(THREAD_NOT_ALIVE);
921 } else {
922 return c.GetResult();
923 }
924}
925
926class GetLocalInstanceClosure : public art::Closure {
927 public:
928 GetLocalInstanceClosure(art::Thread* caller, jint depth, jobject* val)
929 : result_(ERR(INTERNAL)),
930 caller_(caller),
931 depth_(depth),
932 val_(val) {}
933
934 void Run(art::Thread* self) OVERRIDE REQUIRES(art::Locks::mutator_lock_) {
935 art::Locks::mutator_lock_->AssertSharedHeld(art::Thread::Current());
936 std::unique_ptr<art::Context> context(art::Context::Create());
937 FindFrameAtDepthVisitor visitor(self, context.get(), depth_);
938 visitor.WalkStack();
939 if (!visitor.FoundFrame()) {
940 // Must have been a bad depth.
941 result_ = ERR(NO_MORE_FRAMES);
942 return;
943 }
Alex Lightbebd7bd2017-07-25 14:05:52 -0700944 result_ = OK;
945 art::ObjPtr<art::mirror::Object> obj = visitor.GetThisObject();
946 *val_ = obj.IsNull() ? nullptr : caller_->GetJniEnv()->AddLocalReference<jobject>(obj);
947 }
948
949 jvmtiError GetResult() const {
950 return result_;
951 }
952
953 private:
954 jvmtiError result_;
955 art::Thread* caller_;
956 jint depth_;
957 jobject* val_;
958};
959
960jvmtiError MethodUtil::GetLocalInstance(jvmtiEnv* env ATTRIBUTE_UNUSED,
961 jthread thread,
962 jint depth,
963 jobject* data) {
964 if (depth < 0) {
965 return ERR(ILLEGAL_ARGUMENT);
966 }
967 art::Thread* self = art::Thread::Current();
968 art::ScopedObjectAccess soa(self);
Alex Lightb1e31a82017-10-04 16:57:36 -0700969 art::Locks::thread_list_lock_->ExclusiveLock(self);
Alex Light7ddc23d2017-09-22 15:33:41 -0700970 art::Thread* target = nullptr;
971 jvmtiError err = ERR(INTERNAL);
972 if (!ThreadUtil::GetAliveNativeThread(thread, soa, &target, &err)) {
Alex Lightb1e31a82017-10-04 16:57:36 -0700973 art::Locks::thread_list_lock_->ExclusiveUnlock(self);
Alex Light7ddc23d2017-09-22 15:33:41 -0700974 return err;
Alex Lightbebd7bd2017-07-25 14:05:52 -0700975 }
976 GetLocalInstanceClosure c(self, depth, data);
Alex Lightb1e31a82017-10-04 16:57:36 -0700977 // RequestSynchronousCheckpoint releases the thread_list_lock_ as a part of its execution.
Alex Lightbebd7bd2017-07-25 14:05:52 -0700978 if (!target->RequestSynchronousCheckpoint(&c)) {
979 return ERR(THREAD_NOT_ALIVE);
980 } else {
981 return c.GetResult();
982 }
983}
984
985#define FOR_JVMTI_JVALUE_TYPES(fn) \
986 fn(jint, art::Primitive::kPrimInt, i) \
987 fn(jlong, art::Primitive::kPrimLong, j) \
988 fn(jfloat, art::Primitive::kPrimFloat, f) \
989 fn(jdouble, art::Primitive::kPrimDouble, d) \
990 fn(jobject, art::Primitive::kPrimNot, l)
991
992namespace impl {
993
994template<typename T> void WriteJvalue(T, jvalue*);
995template<typename T> void ReadJvalue(jvalue, T*);
996template<typename T> art::Primitive::Type GetJNIType();
997
998#define JNI_TYPE_CHAR(type, prim, id) \
999template<> art::Primitive::Type GetJNIType<type>() { \
1000 return prim; \
1001}
1002
1003FOR_JVMTI_JVALUE_TYPES(JNI_TYPE_CHAR);
1004
1005#undef JNI_TYPE_CHAR
1006
Andreas Gampe49fc60e2017-08-24 13:19:59 -07001007#define RW_JVALUE(srctype, prim, id) \
1008 template<> void ReadJvalue<srctype>(jvalue in, std::add_pointer<srctype>::type out) { \
Alex Lightbebd7bd2017-07-25 14:05:52 -07001009 *out = in.id; \
1010 } \
Andreas Gampe49fc60e2017-08-24 13:19:59 -07001011 template<> void WriteJvalue<srctype>(srctype in, jvalue* out) { \
Alex Lightbebd7bd2017-07-25 14:05:52 -07001012 out->id = in; \
1013 }
1014
1015FOR_JVMTI_JVALUE_TYPES(RW_JVALUE);
1016
1017#undef RW_JVALUE
1018
1019} // namespace impl
1020
1021template<typename T>
1022jvmtiError MethodUtil::SetLocalVariable(jvmtiEnv* env,
1023 jthread thread,
1024 jint depth,
1025 jint slot,
1026 T data) {
1027 jvalue v = {.j = 0};
1028 art::Primitive::Type type = impl::GetJNIType<T>();
1029 impl::WriteJvalue(data, &v);
1030 return SetLocalVariableGeneric(env, thread, depth, slot, type, v);
1031}
1032
1033template<typename T>
1034jvmtiError MethodUtil::GetLocalVariable(jvmtiEnv* env,
1035 jthread thread,
1036 jint depth,
1037 jint slot,
1038 T* data) {
1039 if (data == nullptr) {
1040 return ERR(NULL_POINTER);
1041 }
1042 jvalue v = {.j = 0};
1043 art::Primitive::Type type = impl::GetJNIType<T>();
1044 jvmtiError err = GetLocalVariableGeneric(env, thread, depth, slot, type, &v);
1045 if (err != OK) {
1046 return err;
1047 } else {
1048 impl::ReadJvalue(v, data);
1049 return OK;
1050 }
1051}
1052
Andreas Gampe49fc60e2017-08-24 13:19:59 -07001053#define GET_SET_LV(srctype, prim, id) \
1054 template jvmtiError MethodUtil::GetLocalVariable<srctype>(jvmtiEnv*, \
1055 jthread, \
1056 jint, \
1057 jint, \
1058 std::add_pointer<srctype>::type); \
1059 template jvmtiError MethodUtil::SetLocalVariable<srctype>(jvmtiEnv*, \
1060 jthread, \
1061 jint, \
1062 jint, \
1063 srctype);
Alex Lightbebd7bd2017-07-25 14:05:52 -07001064
1065FOR_JVMTI_JVALUE_TYPES(GET_SET_LV);
1066
1067#undef GET_SET_LV
1068
1069#undef FOR_JVMTI_JVALUE_TYPES
1070
Andreas Gampe3c252f02016-10-27 18:25:17 -07001071} // namespace openjdkjvmti