1 /*
2  * Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  *
23  */
24 
25 #include "precompiled.hpp"
26 #include "jni.h"
27 #include "jvm.h"
28 #include "classfile/vmSymbols.hpp"
29 #include "memory/allocation.inline.hpp"
30 #include "memory/resourceArea.hpp"
31 #include "oops/oop.inline.hpp"
32 #include "runtime/interfaceSupport.inline.hpp"
33 #include "runtime/perfData.inline.hpp"
34 #include "runtime/perfMemory.hpp"
35 
36 /*
37  *      Implementation of class jdk.internal.perf.Perf
38  */
39 
40 
41 #define PERF_ENTRY(result_type, header) \
42   JVM_ENTRY(result_type, header)
43 
44 #define PERF_END JVM_END
45 
46 #define PerfWrapper(arg) /* Unimplemented at this time */
47 
jstr_to_utf(JNIEnv * env,jstring str,TRAPS)48 static char* jstr_to_utf(JNIEnv *env, jstring str, TRAPS) {
49 
50   char* utfstr = NULL;
51 
52   if (str == NULL) {
53     THROW_0(vmSymbols::java_lang_NullPointerException());
54     //throw_new(env,"NullPointerException");
55   }
56 
57   int len = env->GetStringUTFLength(str);
58   int unicode_len = env->GetStringLength(str);
59 
60   utfstr = NEW_RESOURCE_ARRAY(char, len + 1);
61 
62   env->GetStringUTFRegion(str, 0, unicode_len, utfstr);
63 
64   return utfstr;
65 }
66 
67 PERF_ENTRY(jobject, Perf_Attach(JNIEnv *env, jobject unused, jstring user, int vmid, int mode))
68 
69   PerfWrapper("Perf_Attach");
70 
71   char* address = 0;
72   size_t capacity = 0;
73   const char* user_utf = NULL;
74 
75   ResourceMark rm;
76 
77   {
78     ThreadToNativeFromVM ttnfv(thread);
79 
80     user_utf = user == NULL ? NULL : jstr_to_utf(env, user, CHECK_NULL);
81   }
82 
83   if (mode != PerfMemory::PERF_MODE_RO &&
84       mode != PerfMemory::PERF_MODE_RW) {
85     THROW_0(vmSymbols::java_lang_IllegalArgumentException());
86   }
87 
88   // attach to the PerfData memory region for the specified VM
89   PerfMemory::attach(user_utf, vmid, (PerfMemory::PerfMemoryMode) mode,
90                      &address, &capacity, CHECK_NULL);
91 
92   {
93     ThreadToNativeFromVM ttnfv(thread);
94     return env->NewDirectByteBuffer(address, (jlong)capacity);
95   }
96 
97 PERF_END
98 
99 PERF_ENTRY(void, Perf_Detach(JNIEnv *env, jobject unused, jobject buffer))
100 
101   PerfWrapper("Perf_Detach");
102 
103   if (!UsePerfData) {
104     // With -XX:-UsePerfData, detach is just a NOP
105     return;
106   }
107 
108   void* address = 0;
109   jlong capacity = 0;
110 
111   // get buffer address and capacity
112   {
113    ThreadToNativeFromVM ttnfv(thread);
114    address = env->GetDirectBufferAddress(buffer);
115    capacity = env->GetDirectBufferCapacity(buffer);
116   }
117 
118   PerfMemory::detach((char*)address, capacity, CHECK);
119 
120 PERF_END
121 
122 PERF_ENTRY(jobject, Perf_CreateLong(JNIEnv *env, jobject perf, jstring name,
123            int variability, int units, jlong value))
124 
125   PerfWrapper("Perf_CreateLong");
126 
127   char* name_utf = NULL;
128 
129   if (units <= 0 || units > PerfData::U_Last) {
130     debug_only(warning("unexpected units argument, units = %d", units));
131     THROW_0(vmSymbols::java_lang_IllegalArgumentException());
132   }
133 
134   ResourceMark rm;
135 
136   {
137     ThreadToNativeFromVM ttnfv(thread);
138 
139     name_utf = jstr_to_utf(env, name, CHECK_NULL);
140   }
141 
142   PerfLong* pl = NULL;
143 
144   // check that the PerfData name doesn't already exist
145   if (PerfDataManager::exists(name_utf)) {
146     THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "PerfLong name already exists");
147   }
148 
149   switch(variability) {
150   case PerfData::V_Constant:
151     pl = PerfDataManager::create_long_constant(NULL_NS, (char *)name_utf,
152                                                (PerfData::Units)units, value,
153                                                CHECK_NULL);
154     break;
155 
156   case PerfData::V_Monotonic:
157     pl = PerfDataManager::create_long_counter(NULL_NS, (char *)name_utf,
158                                                (PerfData::Units)units, value,
159                                                CHECK_NULL);
160     break;
161 
162   case PerfData::V_Variable:
163     pl = PerfDataManager::create_long_variable(NULL_NS, (char *)name_utf,
164                                               (PerfData::Units)units, value,
165                                               CHECK_NULL);
166     break;
167 
168   default: /* Illegal Argument */
169     debug_only(warning("unexpected variability value: %d", variability));
170     THROW_0(vmSymbols::java_lang_IllegalArgumentException());
171     break;
172   }
173 
174   long* lp = (long*)pl->get_address();
175 
176   {
177     ThreadToNativeFromVM ttnfv(thread);
178     return env->NewDirectByteBuffer(lp, sizeof(jlong));
179   }
180 
181 PERF_END
182 
183 PERF_ENTRY(jobject, Perf_CreateByteArray(JNIEnv *env, jobject perf,
184                                          jstring name, jint variability,
185                                          jint units, jbyteArray value,
186                                          jint maxlength))
187 
188   PerfWrapper("Perf_CreateByteArray");
189 
190   // check for valid byte array objects
191   if (name == NULL || value == NULL) {
192     THROW_0(vmSymbols::java_lang_NullPointerException());
193   }
194 
195   // check for valid variability classification
196   if (variability != PerfData::V_Constant &&
197       variability != PerfData::V_Variable) {
198     debug_only(warning("unexpected variability value: %d", variability));
199     THROW_0(vmSymbols::java_lang_IllegalArgumentException());
200   }
201 
202   // check for valid units
203   if (units != PerfData::U_String) {
204     // only String based ByteArray objects are currently supported
205     debug_only(warning("unexpected units value: %d", variability));
206     THROW_0(vmSymbols::java_lang_IllegalArgumentException());
207   }
208 
209   int value_length;
210   char* name_utf = NULL;
211   jbyte* value_local = NULL;
212 
213   ResourceMark rm;
214 
215   {
216     ThreadToNativeFromVM ttnfv(thread);
217 
218     name_utf = jstr_to_utf(env, name, CHECK_NULL);
219 
220     value_length = env->GetArrayLength(value);
221 
222     value_local = NEW_RESOURCE_ARRAY(jbyte, value_length + 1);
223 
224     env->GetByteArrayRegion(value, 0, value_length, value_local);
225   }
226 
227   // check that the counter name doesn't already exist
228   if (PerfDataManager::exists((char*)name_utf)) {
229     THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "PerfByteArray name already exists");
230   }
231 
232   PerfByteArray* pbv = NULL;
233 
234   if (units == PerfData::U_String) {
235 
236     if (variability == PerfData::V_Constant) {
237       // create the string constant
238       pbv = PerfDataManager::create_string_constant(NULL_NS, (char*)name_utf,
239                                                     (char*)value_local,
240                                                     CHECK_NULL);
241 
242       assert(maxlength == value_length, "string constant length should be == maxlength");
243       maxlength = value_length;
244     }
245     else {
246 
247       // create the string variable
248       pbv = PerfDataManager::create_string_variable(NULL_NS, (char*)name_utf,
249                                                     maxlength,
250                                                     (char*)value_local,
251                                                     CHECK_NULL);
252 
253      assert(maxlength >= value_length,"string variable length should be <= maxlength");
254     }
255   }
256 
257   char* cp = (char*)pbv->get_address();
258 
259   {
260     ThreadToNativeFromVM ttnfv(thread);
261     return env->NewDirectByteBuffer(cp, maxlength+1);
262   }
263 
264 PERF_END
265 
266 PERF_ENTRY(jlong, Perf_HighResCounter(JNIEnv *env, jobject perf))
267 
268   PerfWrapper("Perf_HighResCounter");
269 
270   // this should be a method in java.lang.System. This value could
271   // be acquired through access to a PerfData performance counter, but
272   // doing so would require that the PerfData monitoring overhead be
273   // incurred by all Java applications, which is unacceptable.
274 
275   return os::elapsed_counter();
276 
277 PERF_END
278 
279 PERF_ENTRY(jlong, Perf_HighResFrequency(JNIEnv *env, jobject perf))
280 
281   PerfWrapper("Perf_HighResFrequency");
282 
283   // this should be a method in java.lang.System. This value could
284   // be acquired through access to a PerfData performance counter, but
285   // doing so would require that the PerfData monitoring overhead be
286   // incurred by all Java applications, which is unacceptable.
287 
288   return os::elapsed_frequency();
289 
290 PERF_END
291 
292 /// JVM_RegisterPerfMethods
293 
294 #define CC (char*)  /*cast a literal from (const char*)*/
295 #define FN_PTR(f) CAST_FROM_FN_PTR(void*, &f)
296 #define BB "Ljava/nio/ByteBuffer;"
297 #define JLS "Ljava/lang/String;"
298 #define CL_ARGS     CC "(" JLS "IIJ)" BB
299 #define CBA_ARGS    CC "(" JLS "II[BI)" BB
300 
301 static JNINativeMethod perfmethods[] = {
302 
303   {CC "attach",              CC "(" JLS "II)" BB, FN_PTR(Perf_Attach)},
304   {CC "detach",              CC "(" BB ")V",      FN_PTR(Perf_Detach)},
305   {CC "createLong",          CL_ARGS,             FN_PTR(Perf_CreateLong)},
306   {CC "createByteArray",     CBA_ARGS,            FN_PTR(Perf_CreateByteArray)},
307   {CC "highResCounter",      CC "()J",            FN_PTR(Perf_HighResCounter)},
308   {CC "highResFrequency",    CC "()J",            FN_PTR(Perf_HighResFrequency)}
309 };
310 
311 #undef CBA_ARGS
312 #undef CL_ARGS
313 #undef JLS
314 #undef BB
315 #undef FN_PTR
316 #undef CC
317 
318 // This one function is exported, used by NativeLookup.
319 JVM_ENTRY(void, JVM_RegisterPerfMethods(JNIEnv *env, jclass perfclass))
320   PerfWrapper("JVM_RegisterPerfMethods");
321   {
322     ThreadToNativeFromVM ttnfv(thread);
323     int ok = env->RegisterNatives(perfclass, perfmethods, sizeof(perfmethods)/sizeof(JNINativeMethod));
324     guarantee(ok == 0, "register perf natives");
325   }
326 JVM_END
327