1/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "common_helper.h"
18
19#include "jni.h"
20#include "jvmti.h"
21
22#include "jvmti_helper.h"
23#include "scoped_local_ref.h"
24#include "test_env.h"
25
26namespace art {
27namespace common_locals {
28
29static void DeallocateContents(jvmtiLocalVariableEntry* vars, jint nvars) {
30  for (jint i = 0; i < nvars; i++) {
31    jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(vars[i].name));
32    jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(vars[i].signature));
33    jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(vars[i].generic_signature));
34  }
35}
36
37extern "C" JNIEXPORT void Java_art_Locals_EnableLocalVariableAccess(JNIEnv* env, jclass) {
38  jvmtiCapabilities caps;
39  if (JvmtiErrorToException(env, jvmti_env, jvmti_env->GetCapabilities(&caps))) {
40    return;
41  }
42  caps.can_access_local_variables = 1;
43  JvmtiErrorToException(env, jvmti_env, jvmti_env->AddCapabilities(&caps));
44}
45
46extern "C" JNIEXPORT void Java_art_Locals_SetLocalVariableObject(JNIEnv* env,
47                                                                 jclass,
48                                                                 jthread t,
49                                                                 jint depth,
50                                                                 jint slot,
51                                                                 jobject val) {
52  JvmtiErrorToException(env, jvmti_env, jvmti_env->SetLocalObject(t, depth, slot, val));
53}
54
55extern "C" JNIEXPORT void Java_art_Locals_SetLocalVariableDouble(JNIEnv* env,
56                                                                 jclass,
57                                                                 jthread t,
58                                                                 jint depth,
59                                                                 jint slot,
60                                                                 jdouble val) {
61  JvmtiErrorToException(env, jvmti_env, jvmti_env->SetLocalDouble(t, depth, slot, val));
62}
63
64extern "C" JNIEXPORT void Java_art_Locals_SetLocalVariableFloat(JNIEnv* env,
65                                                                jclass,
66                                                                jthread t,
67                                                                jint depth,
68                                                                jint slot,
69                                                                jfloat val) {
70  JvmtiErrorToException(env, jvmti_env, jvmti_env->SetLocalFloat(t, depth, slot, val));
71}
72
73extern "C" JNIEXPORT void Java_art_Locals_SetLocalVariableLong(JNIEnv* env,
74                                                               jclass,
75                                                               jthread t,
76                                                               jint depth,
77                                                               jint slot,
78                                                               jlong val) {
79  JvmtiErrorToException(env, jvmti_env, jvmti_env->SetLocalLong(t, depth, slot, val));
80}
81
82extern "C" JNIEXPORT void Java_art_Locals_SetLocalVariableInt(JNIEnv* env,
83                                                              jclass,
84                                                              jthread t,
85                                                              jint depth,
86                                                              jint slot,
87                                                              jint val) {
88  JvmtiErrorToException(env, jvmti_env, jvmti_env->SetLocalInt(t, depth, slot, val));
89}
90
91extern "C" JNIEXPORT jdouble Java_art_Locals_GetLocalVariableDouble(JNIEnv* env,
92                                                                    jclass,
93                                                                    jthread t,
94                                                                    jint depth,
95                                                                    jint slot) {
96  jdouble ret = 0;
97  JvmtiErrorToException(env, jvmti_env, jvmti_env->GetLocalDouble(t, depth, slot, &ret));
98  return ret;
99}
100
101extern "C" JNIEXPORT jfloat Java_art_Locals_GetLocalVariableFloat(JNIEnv* env,
102                                                                  jclass,
103                                                                  jthread t,
104                                                                  jint depth,
105                                                                  jint slot) {
106  jfloat ret = 0;
107  JvmtiErrorToException(env, jvmti_env, jvmti_env->GetLocalFloat(t, depth, slot, &ret));
108  return ret;
109}
110
111extern "C" JNIEXPORT jlong Java_art_Locals_GetLocalVariableLong(JNIEnv* env,
112                                                                jclass,
113                                                                jthread t,
114                                                                jint depth,
115                                                                jint slot) {
116  jlong ret = 0;
117  JvmtiErrorToException(env, jvmti_env, jvmti_env->GetLocalLong(t, depth, slot, &ret));
118  return ret;
119}
120
121extern "C" JNIEXPORT jint Java_art_Locals_GetLocalVariableInt(JNIEnv* env,
122                                                              jclass,
123                                                              jthread t,
124                                                              jint depth,
125                                                              jint slot) {
126  jint ret = 0;
127  JvmtiErrorToException(env, jvmti_env, jvmti_env->GetLocalInt(t, depth, slot, &ret));
128  return ret;
129}
130
131extern "C" JNIEXPORT jobject Java_art_Locals_GetLocalInstance(JNIEnv* env,
132                                                              jclass,
133                                                              jthread t,
134                                                              jint depth) {
135  jobject ret = nullptr;
136  JvmtiErrorToException(env, jvmti_env, jvmti_env->GetLocalInstance(t, depth, &ret));
137  return ret;
138}
139
140extern "C" JNIEXPORT jobject Java_art_Locals_GetLocalVariableObject(JNIEnv* env,
141                                                                    jclass,
142                                                                    jthread t,
143                                                                    jint depth,
144                                                                    jint slot) {
145  jobject ret = nullptr;
146  JvmtiErrorToException(env, jvmti_env, jvmti_env->GetLocalObject(t, depth, slot, &ret));
147  return ret;
148}
149
150extern "C" JNIEXPORT jobjectArray Java_art_Locals_GetLocalVariableTable(JNIEnv* env,
151                                                                        jclass,
152                                                                        jobject m) {
153  jmethodID method = env->FromReflectedMethod(m);
154  if (env->ExceptionCheck()) {
155    return nullptr;
156  }
157  ScopedLocalRef<jclass> klass(env, env->FindClass("art/Locals$VariableDescription"));
158  if (env->ExceptionCheck()) {
159    return nullptr;
160  }
161  jint nvars;
162  jvmtiLocalVariableEntry* vars = nullptr;
163  if (JvmtiErrorToException(env, jvmti_env,
164                            jvmti_env->GetLocalVariableTable(method, &nvars, &vars))) {
165    return nullptr;
166  }
167  jobjectArray vars_array = env->NewObjectArray(nvars, klass.get(), nullptr);
168  if (env->ExceptionCheck()) {
169    DeallocateContents(vars, nvars);
170    jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(vars));
171    return nullptr;
172  }
173
174  jmethodID constructor = env->GetMethodID(
175      klass.get(), "<init>", "(JILjava/lang/String;Ljava/lang/String;Ljava/lang/String;I)V");
176  if (env->ExceptionCheck()) {
177    return nullptr;
178  }
179  for (jint i = 0; i < nvars; i++) {
180    ScopedLocalRef<jstring> name_string(env, env->NewStringUTF(vars[i].name));
181    ScopedLocalRef<jstring> sig_string(env, env->NewStringUTF(vars[i].signature));
182    ScopedLocalRef<jstring> generic_sig_string(env, env->NewStringUTF(vars[i].generic_signature));
183    jobject var_obj = env->NewObject(klass.get(),
184                                     constructor,
185                                     vars[i].start_location,
186                                     vars[i].length,
187                                     name_string.get(),
188                                     sig_string.get(),
189                                     generic_sig_string.get(),
190                                     vars[i].slot);
191    if (env->ExceptionCheck()) {
192      DeallocateContents(vars, nvars);
193      jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(vars));
194      return nullptr;
195    }
196    env->SetObjectArrayElement(vars_array, i, var_obj);
197    if (env->ExceptionCheck()) {
198      DeallocateContents(vars, nvars);
199      jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(vars));
200      return nullptr;
201    }
202  }
203
204  DeallocateContents(vars, nvars);
205  jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(vars));
206  return vars_array;
207}
208
209}  // namespace common_locals
210}  // namespace art
211