--- /dev/null 2019-02-13 16:01:02.292000000 +0300 +++ new/src/share/vm/jfr/jni/jfrJavaCall.cpp 2019-02-15 19:02:59.766053501 +0300 @@ -0,0 +1,380 @@ +/* + * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "classfile/symbolTable.hpp" +#include "classfile/systemDictionary.hpp" +#include "jfr/jni/jfrJavaCall.hpp" +#include "jfr/jni/jfrJavaSupport.hpp" +#include "memory/resourceArea.hpp" +#include "runtime/handles.inline.hpp" +#include "runtime/javaCalls.hpp" +#include "utilities/globalDefinitions.hpp" + +#ifdef ASSERT +static bool is_large_value(const JavaValue& value) { + return value.get_type() == T_LONG || value.get_type() == T_DOUBLE; +} +#endif // ASSERT + +static Symbol* resolve(const char* str, TRAPS) { + assert(str != NULL, "invariant"); + return SymbolTable::lookup(str, (int)strlen(str), THREAD); +} + +static Klass* resolve(Symbol* k_sym, TRAPS) { + assert(k_sym != NULL, "invariant"); + return SystemDictionary::resolve_or_fail(k_sym, true, THREAD); +} + +JfrJavaArguments::Parameters::Parameters() : _storage_index(0), _java_stack_slots(0) { + JavaValue value(T_VOID); + push(value); +} + +void JfrJavaArguments::Parameters::push(const JavaValue& value) { + assert(_storage != NULL, "invariant"); + assert(!is_large_value(value), "invariant"); + assert(_storage_index < SIZE, "invariant"); + _storage[_storage_index++] = value; + _java_stack_slots++; +} + +void JfrJavaArguments::Parameters::push_large(const JavaValue& value) { + assert(_storage != NULL, "invariant"); + assert(is_large_value(value), "invariant"); + assert(_storage_index < SIZE, "invariant"); + _storage[_storage_index++] = value; + _java_stack_slots += 2; +} + +void JfrJavaArguments::Parameters::set_receiver(const oop receiver) { + assert(_storage != NULL, "invariant"); + assert(receiver != NULL, "invariant"); + JavaValue value(T_OBJECT); + value.set_jobject((jobject)receiver); + _storage[0] = value; +} + +void JfrJavaArguments::Parameters::set_receiver(Handle receiver) { + set_receiver(receiver()); +} + +oop JfrJavaArguments::Parameters::receiver() const { + assert(has_receiver(), "invariant"); + assert(_storage[0].get_type() == T_OBJECT, "invariant"); + return (oop)_storage[0].get_jobject(); +} + +bool JfrJavaArguments::Parameters::has_receiver() const { + assert(_storage != NULL, "invariant"); + assert(_storage_index >= 1, "invariant"); + assert(_java_stack_slots >= 1, "invariant"); + return _storage[0].get_type() == T_OBJECT; +} + +void JfrJavaArguments::Parameters::push_oop(const oop obj) { + JavaValue value(T_OBJECT); + value.set_jobject((jobject)obj); + push(value); +} + +void JfrJavaArguments::Parameters::push_oop(Handle h_obj) { + push_oop(h_obj()); +} + +void JfrJavaArguments::Parameters::push_jobject(jobject h) { + JavaValue value(T_ADDRESS); + value.set_jobject(h); + push(value); +} + +void JfrJavaArguments::Parameters::push_jint(jint i) { + JavaValue value(T_INT); + value.set_jint(i); + push(value); +} + +void JfrJavaArguments::Parameters::push_jfloat(jfloat f) { + JavaValue value(T_FLOAT); + value.set_jfloat(f); + push(value); +} + +void JfrJavaArguments::Parameters::push_jdouble(jdouble d) { + JavaValue value(T_DOUBLE); + value.set_jdouble(d); + push_large(value); +} + +void JfrJavaArguments::Parameters::push_jlong(jlong l) { + JavaValue value(T_LONG); + value.set_jlong(l); + push_large(value); +} + +// including receiver (even if there is none) +inline int JfrJavaArguments::Parameters::length() const { + assert(_storage_index >= 1, "invariant"); + return _storage_index; +} + +inline int JfrJavaArguments::Parameters::java_stack_slots() const { + return _java_stack_slots; +} + +const JavaValue& JfrJavaArguments::Parameters::values(int idx) const { + assert(idx >= 0, "invariant"); + assert(idx < SIZE, "invariant"); + return _storage[idx]; +} + +void JfrJavaArguments::Parameters::copy(JavaCallArguments& args, TRAPS) const { + DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD)); + if (has_receiver()) { + args.set_receiver(Handle(THREAD, receiver())); + } + for (int i = 1; i < length(); ++i) { + switch(values(i).get_type()) { + case T_BOOLEAN: + case T_CHAR: + case T_SHORT: + case T_INT: + args.push_int(values(i).get_jint()); + break; + case T_LONG: + args.push_long(values(i).get_jlong()); + break; + case T_FLOAT: + args.push_float(values(i).get_jfloat()); + break; + case T_DOUBLE: + args.push_double(values(i).get_jdouble()); + break; + case T_OBJECT: + args.push_oop(Handle(THREAD, (oop)values(i).get_jobject())); + break; + case T_ADDRESS: + args.push_oop(Handle(THREAD, JNIHandles::resolve(values(i).get_jobject()))); + break; + default: + ShouldNotReachHere(); + } + } +} + +JfrJavaArguments::JfrJavaArguments(JavaValue* result) : _result(result), _klass(NULL), _name(NULL), _signature(NULL), _array_length(0) { + assert(result != NULL, "invariant"); +} + +JfrJavaArguments::JfrJavaArguments(JavaValue* result, const char* klass_name, const char* name, const char* signature, TRAPS) : + _result(result), + _klass(NULL), + _name(NULL), + _signature(NULL), + _array_length(0) { + assert(result != NULL, "invariant"); + if (klass_name != NULL) { + set_klass(klass_name, CHECK); + } + if (name != NULL) { + set_name(name, CHECK); + } + if (signature != NULL) { + set_signature(signature, THREAD); + } +} + +JfrJavaArguments::JfrJavaArguments(JavaValue* result, const Klass* klass, const Symbol* name, const Symbol* signature) : _result(result), + _klass(NULL), + _name(NULL), + _signature(NULL), + _array_length(0) { + assert(result != NULL, "invariant"); + if (klass != NULL) { + set_klass(klass); + } + if (name != NULL) { + set_name(name); + } + if (signature != NULL) { + set_signature(signature); + } +} + +Klass* JfrJavaArguments::klass() const { + assert(_klass != NULL, "invariant"); + return const_cast(_klass); +} + +void JfrJavaArguments::set_klass(const char* klass_name, TRAPS) { + assert(klass_name != NULL, "invariant"); + Symbol* const k_sym = resolve(klass_name, CHECK); + assert(k_sym != NULL, "invariant"); + const Klass* const klass = resolve(k_sym, CHECK); + set_klass(klass); +} + +void JfrJavaArguments::set_klass(const Klass* klass) { + assert(klass != NULL, "invariant"); + _klass = klass; +} + +Symbol* JfrJavaArguments::name() const { + assert(_name != NULL, "invariant"); + return const_cast(_name); +} + +void JfrJavaArguments::set_name(const char* name, TRAPS) { + assert(name != NULL, "invariant"); + const Symbol* const sym = resolve(name, CHECK); + set_name(sym); +} + +void JfrJavaArguments::set_name(const Symbol* name) { + assert(name != NULL, "invariant"); + _name = name; +} + +Symbol* JfrJavaArguments::signature() const { + assert(_signature != NULL, "invariant"); + return const_cast(_signature); +} + +void JfrJavaArguments::set_signature(const char* signature, TRAPS) { + assert(signature != NULL, "invariant"); + const Symbol* const sym = resolve(signature, CHECK); + set_signature(sym); +} + +void JfrJavaArguments::set_signature(const Symbol* signature) { + assert(signature != NULL, "invariant"); + _signature = signature; +} + +int JfrJavaArguments::array_length() const { + return _array_length; +} + +void JfrJavaArguments::set_array_length(int length) { + assert(length >= 0, "invariant"); + _array_length = length; +} + +JavaValue* JfrJavaArguments::result() const { + assert(_result != NULL, "invariant"); + return const_cast(_result); +} + +int JfrJavaArguments::length() const { + return _params.length(); +} + +bool JfrJavaArguments::has_receiver() const { + return _params.has_receiver(); +} + +oop JfrJavaArguments::receiver() const { + return _params.receiver(); +} + +void JfrJavaArguments::set_receiver(const oop receiver) { + _params.set_receiver(receiver); +} + +void JfrJavaArguments::set_receiver(Handle receiver) { + _params.set_receiver(receiver); +} + +void JfrJavaArguments::push_oop(const oop obj) { + _params.push_oop(obj); +} + +void JfrJavaArguments::push_oop(Handle h_obj) { + _params.push_oop(h_obj); +} + +void JfrJavaArguments::push_jobject(jobject h) { + _params.push_jobject(h); +} + +void JfrJavaArguments::push_int(jint i) { + _params.push_jint(i); +} + +void JfrJavaArguments::push_float(jfloat f) { + _params.push_jfloat(f); +} + +void JfrJavaArguments::push_double(jdouble d) { + _params.push_jdouble(d); +} + +void JfrJavaArguments::push_long(jlong l) { + _params.push_jlong(l); +} + +const JavaValue& JfrJavaArguments::param(int idx) const { + return _params.values(idx); +} + +int JfrJavaArguments::java_call_arg_slots() const { + return _params.java_stack_slots(); +} + +void JfrJavaArguments::copy(JavaCallArguments& args, TRAPS) { + _params.copy(args, THREAD); +} + +void JfrJavaCall::call_static(JfrJavaArguments* args, TRAPS) { + assert(args != NULL, "invariant"); + DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD)); + ResourceMark rm(THREAD); + HandleMark hm(THREAD); + JavaCallArguments jcas(args->java_call_arg_slots()); + args->copy(jcas, CHECK); + JavaCalls::call_static(args->result(), args->klass(), args->name(), args->signature(), &jcas, THREAD); +} + +void JfrJavaCall::call_special(JfrJavaArguments* args, TRAPS) { + assert(args != NULL, "invariant"); + assert(args->has_receiver(), "invariant"); + DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD)); + ResourceMark rm(THREAD); + HandleMark hm(THREAD); + JavaCallArguments jcas(args->java_call_arg_slots()); + args->copy(jcas, CHECK); + JavaCalls::call_special(args->result(), args->klass(), args->name(), args->signature(), &jcas, THREAD); +} + +void JfrJavaCall::call_virtual(JfrJavaArguments* args, TRAPS) { + assert(args != NULL, "invariant"); + assert(args->has_receiver(), "invariant"); + DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD)); + ResourceMark rm(THREAD); + HandleMark hm(THREAD); + JavaCallArguments jcas(args->java_call_arg_slots()); + args->copy(jcas, CHECK); + JavaCalls::call_virtual(args->result(), args->klass(), args->name(), args->signature(), &jcas, THREAD); +}