1/*
2 * Copyright (c) 2017, 2019, 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 "classfile/symbolTable.hpp"
27#include "classfile/systemDictionary.hpp"
28#include "jfr/jni/jfrJavaCall.hpp"
29#include "jfr/jni/jfrJavaSupport.hpp"
30#include "memory/resourceArea.hpp"
31#include "runtime/handles.inline.hpp"
32#include "runtime/javaCalls.hpp"
33#include "utilities/globalDefinitions.hpp"
34
35#ifdef ASSERT
36static bool is_large_value(const JavaValue& value) {
37 return value.get_type() == T_LONG || value.get_type() == T_DOUBLE;
38}
39#endif // ASSERT
40
41static Symbol* resolve(const char* str) {
42 assert(str != NULL, "invariant");
43 return SymbolTable::new_symbol(str);
44}
45
46static Klass* resolve(Symbol* k_sym, TRAPS) {
47 assert(k_sym != NULL, "invariant");
48 return SystemDictionary::resolve_or_fail(k_sym, true, THREAD);
49}
50
51JfrJavaArguments::Parameters::Parameters() : _storage_index(0), _java_stack_slots(0) {
52 JavaValue value(T_VOID);
53 push(value);
54}
55
56void JfrJavaArguments::Parameters::push(const JavaValue& value) {
57 assert(_storage != NULL, "invariant");
58 assert(!is_large_value(value), "invariant");
59 assert(_storage_index < SIZE, "invariant");
60 _storage[_storage_index++] = value;
61 _java_stack_slots++;
62}
63
64void JfrJavaArguments::Parameters::push_large(const JavaValue& value) {
65 assert(_storage != NULL, "invariant");
66 assert(is_large_value(value), "invariant");
67 assert(_storage_index < SIZE, "invariant");
68 _storage[_storage_index++] = value;
69 _java_stack_slots += 2;
70}
71
72void JfrJavaArguments::Parameters::set_receiver(const oop receiver) {
73 assert(_storage != NULL, "invariant");
74 assert(receiver != NULL, "invariant");
75 JavaValue value(T_OBJECT);
76 value.set_jobject((jobject)receiver);
77 _storage[0] = value;
78}
79
80void JfrJavaArguments::Parameters::set_receiver(Handle receiver) {
81 set_receiver(receiver());
82}
83
84oop JfrJavaArguments::Parameters::receiver() const {
85 assert(has_receiver(), "invariant");
86 assert(_storage[0].get_type() == T_OBJECT, "invariant");
87 return (oop)_storage[0].get_jobject();
88}
89
90bool JfrJavaArguments::Parameters::has_receiver() const {
91 assert(_storage != NULL, "invariant");
92 assert(_storage_index >= 1, "invariant");
93 assert(_java_stack_slots >= 1, "invariant");
94 return _storage[0].get_type() == T_OBJECT;
95}
96
97void JfrJavaArguments::Parameters::push_oop(const oop obj) {
98 JavaValue value(T_OBJECT);
99 value.set_jobject((jobject)obj);
100 push(value);
101}
102
103void JfrJavaArguments::Parameters::push_oop(Handle h_obj) {
104 push_oop(h_obj());
105}
106
107void JfrJavaArguments::Parameters::push_jobject(jobject h) {
108 JavaValue value(T_ADDRESS);
109 value.set_jobject(h);
110 push(value);
111}
112
113void JfrJavaArguments::Parameters::push_jint(jint i) {
114 JavaValue value(T_INT);
115 value.set_jint(i);
116 push(value);
117}
118
119void JfrJavaArguments::Parameters::push_jfloat(jfloat f) {
120 JavaValue value(T_FLOAT);
121 value.set_jfloat(f);
122 push(value);
123}
124
125void JfrJavaArguments::Parameters::push_jdouble(jdouble d) {
126 JavaValue value(T_DOUBLE);
127 value.set_jdouble(d);
128 push_large(value);
129}
130
131void JfrJavaArguments::Parameters::push_jlong(jlong l) {
132 JavaValue value(T_LONG);
133 value.set_jlong(l);
134 push_large(value);
135}
136
137// including receiver (even if there is none)
138inline int JfrJavaArguments::Parameters::length() const {
139 assert(_storage_index >= 1, "invariant");
140 return _storage_index;
141}
142
143inline int JfrJavaArguments::Parameters::java_stack_slots() const {
144 return _java_stack_slots;
145}
146
147const JavaValue& JfrJavaArguments::Parameters::values(int idx) const {
148 assert(idx >= 0, "invariant");
149 assert(idx < SIZE, "invariant");
150 return _storage[idx];
151}
152
153void JfrJavaArguments::Parameters::copy(JavaCallArguments& args, TRAPS) const {
154 DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
155 if (has_receiver()) {
156 args.set_receiver(Handle(THREAD, receiver()));
157 }
158 for (int i = 1; i < length(); ++i) {
159 switch(values(i).get_type()) {
160 case T_BOOLEAN:
161 case T_CHAR:
162 case T_SHORT:
163 case T_INT:
164 args.push_int(values(i).get_jint());
165 break;
166 case T_LONG:
167 args.push_long(values(i).get_jlong());
168 break;
169 case T_FLOAT:
170 args.push_float(values(i).get_jfloat());
171 break;
172 case T_DOUBLE:
173 args.push_double(values(i).get_jdouble());
174 break;
175 case T_OBJECT:
176 args.push_oop(Handle(THREAD, (oop)values(i).get_jobject()));
177 break;
178 case T_ADDRESS:
179 args.push_jobject(values(i).get_jobject());
180 break;
181 default:
182 ShouldNotReachHere();
183 }
184 }
185}
186
187JfrJavaArguments::JfrJavaArguments(JavaValue* result) : _result(result), _klass(NULL), _name(NULL), _signature(NULL), _array_length(-1) {
188 assert(result != NULL, "invariant");
189}
190
191JfrJavaArguments::JfrJavaArguments(JavaValue* result, const char* klass_name, const char* name, const char* signature, TRAPS) :
192 _result(result),
193 _klass(NULL),
194 _name(NULL),
195 _signature(NULL),
196 _array_length(-1) {
197 assert(result != NULL, "invariant");
198 if (klass_name != NULL) {
199 set_klass(klass_name, CHECK);
200 }
201 if (name != NULL) {
202 set_name(name);
203 }
204 if (signature != NULL) {
205 set_signature(signature);
206 }
207}
208
209JfrJavaArguments::JfrJavaArguments(JavaValue* result, const Klass* klass, const Symbol* name, const Symbol* signature) : _result(result),
210 _klass(NULL),
211 _name(NULL),
212 _signature(NULL),
213 _array_length(-1) {
214 assert(result != NULL, "invariant");
215 if (klass != NULL) {
216 set_klass(klass);
217 }
218 if (name != NULL) {
219 set_name(name);
220 }
221 if (signature != NULL) {
222 set_signature(signature);
223 }
224}
225
226Klass* JfrJavaArguments::klass() const {
227 assert(_klass != NULL, "invariant");
228 return const_cast<Klass*>(_klass);
229}
230
231void JfrJavaArguments::set_klass(const char* klass_name, TRAPS) {
232 assert(klass_name != NULL, "invariant");
233 Symbol* const k_sym = resolve(klass_name);
234 assert(k_sym != NULL, "invariant");
235 const Klass* const klass = resolve(k_sym, CHECK);
236 set_klass(klass);
237}
238
239void JfrJavaArguments::set_klass(const Klass* klass) {
240 assert(klass != NULL, "invariant");
241 _klass = klass;
242}
243
244Symbol* JfrJavaArguments::name() const {
245 assert(_name != NULL, "invariant");
246 return const_cast<Symbol*>(_name);
247}
248
249void JfrJavaArguments::set_name(const char* name) {
250 assert(name != NULL, "invariant");
251 const Symbol* const sym = resolve(name);
252 set_name(sym);
253}
254
255void JfrJavaArguments::set_name(const Symbol* name) {
256 assert(name != NULL, "invariant");
257 _name = name;
258}
259
260Symbol* JfrJavaArguments::signature() const {
261 assert(_signature != NULL, "invariant");
262 return const_cast<Symbol*>(_signature);
263}
264
265void JfrJavaArguments::set_signature(const char* signature) {
266 assert(signature != NULL, "invariant");
267 const Symbol* const sym = resolve(signature);
268 set_signature(sym);
269}
270
271void JfrJavaArguments::set_signature(const Symbol* signature) {
272 assert(signature != NULL, "invariant");
273 _signature = signature;
274}
275
276int JfrJavaArguments::array_length() const {
277 return _array_length;
278}
279
280void JfrJavaArguments::set_array_length(int length) {
281 assert(length >= 0, "invariant");
282 _array_length = length;
283}
284
285JavaValue* JfrJavaArguments::result() const {
286 assert(_result != NULL, "invariant");
287 return const_cast<JavaValue*>(_result);
288}
289
290int JfrJavaArguments::length() const {
291 return _params.length();
292}
293
294bool JfrJavaArguments::has_receiver() const {
295 return _params.has_receiver();
296}
297
298oop JfrJavaArguments::receiver() const {
299 return _params.receiver();
300}
301
302void JfrJavaArguments::set_receiver(const oop receiver) {
303 _params.set_receiver(receiver);
304}
305
306void JfrJavaArguments::set_receiver(Handle receiver) {
307 _params.set_receiver(receiver);
308}
309
310void JfrJavaArguments::push_oop(const oop obj) {
311 _params.push_oop(obj);
312}
313
314void JfrJavaArguments::push_oop(Handle h_obj) {
315 _params.push_oop(h_obj);
316}
317
318void JfrJavaArguments::push_jobject(jobject h) {
319 _params.push_jobject(h);
320}
321
322void JfrJavaArguments::push_int(jint i) {
323 _params.push_jint(i);
324}
325
326void JfrJavaArguments::push_float(jfloat f) {
327 _params.push_jfloat(f);
328}
329
330void JfrJavaArguments::push_double(jdouble d) {
331 _params.push_jdouble(d);
332}
333
334void JfrJavaArguments::push_long(jlong l) {
335 _params.push_jlong(l);
336}
337
338const JavaValue& JfrJavaArguments::param(int idx) const {
339 return _params.values(idx);
340}
341
342int JfrJavaArguments::java_call_arg_slots() const {
343 return _params.java_stack_slots();
344}
345
346void JfrJavaArguments::copy(JavaCallArguments& args, TRAPS) {
347 _params.copy(args, THREAD);
348}
349
350void JfrJavaCall::call_static(JfrJavaArguments* args, TRAPS) {
351 assert(args != NULL, "invariant");
352 DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
353 ResourceMark rm(THREAD);
354 HandleMark hm(THREAD);
355 JavaCallArguments jcas(args->java_call_arg_slots());
356 args->copy(jcas, CHECK);
357 JavaCalls::call_static(args->result(), args->klass(), args->name(), args->signature(), &jcas, THREAD);
358}
359
360void JfrJavaCall::call_special(JfrJavaArguments* args, TRAPS) {
361 assert(args != NULL, "invariant");
362 assert(args->has_receiver(), "invariant");
363 DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
364 ResourceMark rm(THREAD);
365 HandleMark hm(THREAD);
366 JavaCallArguments jcas(args->java_call_arg_slots());
367 args->copy(jcas, CHECK);
368 JavaCalls::call_special(args->result(), args->klass(), args->name(), args->signature(), &jcas, THREAD);
369}
370
371void JfrJavaCall::call_virtual(JfrJavaArguments* args, TRAPS) {
372 assert(args != NULL, "invariant");
373 assert(args->has_receiver(), "invariant");
374 DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
375 ResourceMark rm(THREAD);
376 HandleMark hm(THREAD);
377 JavaCallArguments jcas(args->java_call_arg_slots());
378 args->copy(jcas, CHECK);
379 JavaCalls::call_virtual(args->result(), args->klass(), args->name(), args->signature(), &jcas, THREAD);
380}
381