/* * Copyright (c) 2017, 2019, 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_jobject(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); }