/* * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012 Red Hat, Inc. * Copyright (c) 2021, Azul Systems, Inc. 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. *
*/
// The DT_RETURN_MARK macros create a scoped object to fire the dtrace // '-return' probe regardless of the return path is taken out of the function. // Methods that have multiple return paths use this to avoid having to // instrument each return path. Methods that use CHECK or THROW must use this // since those macros can cause an immediate uninstrumented return. // // In order to get the return value, a reference to the variable containing // the return value must be passed to the constructor of the object, and // the return value must be set before return (since the mark object has // a reference to it). // // Example: // DT_RETURN_MARK_DECL(SomeFunc, int); // JNI_ENTRY(int, SomeFunc, ...) // int return_value = 0; // DT_RETURN_MARK(SomeFunc, int, (const int&)return_value); // foo(CHECK_0) // return_value = 5; // return return_value; // JNI_END #define DT_RETURN_MARK_DECL(name, type, probe) \
DTRACE_ONLY( \ class DTraceReturnProbeMark_##name { \ public: \ const type& _ret_ref; \
DTraceReturnProbeMark_##name(const type& v) : _ret_ref(v) {} \
~DTraceReturnProbeMark_##name() { \
probe; \
} \
} \
) // Void functions are simpler since there's no return value #define DT_VOID_RETURN_MARK_DECL(name, probe) \
DTRACE_ONLY( \ class DTraceReturnProbeMark_##name { \ public: \
~DTraceReturnProbeMark_##name() { \
probe; \
} \
} \
)
// Place these macros in the function to mark the return. Non-void // functions need the type and address of the return value. #define DT_RETURN_MARK(name, type, ref) \
DTRACE_ONLY( DTraceReturnProbeMark_##name dtrace_return_mark(ref) ) #define DT_VOID_RETURN_MARK(name) \
DTRACE_ONLY( DTraceReturnProbeMark_##name dtrace_return_mark )
// Use these to select distinct code for floating-point vs. non-floating point // situations. Used from within common macros where we need slightly // different behavior for Float/Double #define FP_SELECT_Boolean(intcode, fpcode) intcode #define FP_SELECT_Byte(intcode, fpcode) intcode #define FP_SELECT_Char(intcode, fpcode) intcode #define FP_SELECT_Short(intcode, fpcode) intcode #define FP_SELECT_Object(intcode, fpcode) intcode #define FP_SELECT_Int(intcode, fpcode) intcode #define FP_SELECT_Long(intcode, fpcode) intcode #define FP_SELECT_Float(intcode, fpcode) fpcode #define FP_SELECT_Double(intcode, fpcode) fpcode #define FP_SELECT(TypeName, intcode, fpcode) \
FP_SELECT_##TypeName(intcode, fpcode)
// out-of-line helpers for class jfieldIDWorkaround:
bool jfieldIDWorkaround::is_valid_jfieldID(Klass* k, jfieldID id) { if (jfieldIDWorkaround::is_instance_jfieldID(k, id)) {
uintptr_t as_uint = (uintptr_t) id;
intptr_t offset = raw_instance_offset(id); if (is_checked_jfieldID(id)) { if (!klass_hash_ok(k, id)) { returnfalse;
}
} return InstanceKlass::cast(k)->contains_field_offset(offset);
} else {
JNIid* result = (JNIid*) id; #ifdef ASSERT return result != NULL && result->is_static_field_id(); #else return result != NULL; #endif
}
}
intptr_t jfieldIDWorkaround::encode_klass_hash(Klass* k, intptr_t offset) { if (offset <= small_offset_mask) {
Klass* field_klass = k;
Klass* super_klass = field_klass->super(); // With compressed oops the most super class with nonstatic fields would // be the owner of fields embedded in the header. while (InstanceKlass::cast(super_klass)->has_nonstatic_fields() &&
InstanceKlass::cast(super_klass)->contains_field_offset(offset)) {
field_klass = super_klass; // super contains the field also
super_klass = field_klass->super();
}
debug_only(NoSafepointVerifier nosafepoint;)
uintptr_t klass_hash = field_klass->identity_hash(); return ((klass_hash & klass_mask) << klass_shift) | checked_mask_in_place;
} else { #if 0 #ifndef PRODUCT
{
ResourceMark rm;
warning("VerifyJNIFields: long offset %d in %s", offset, k->external_name());
} #endif #endif return 0;
}
}
bool jfieldIDWorkaround::klass_hash_ok(Klass* k, jfieldID id) {
uintptr_t as_uint = (uintptr_t) id;
intptr_t klass_hash = (as_uint >> klass_shift) & klass_mask; do {
debug_only(NoSafepointVerifier nosafepoint;) // Could use a non-blocking query for identity_hash here... if ((k->identity_hash() & klass_mask) == klass_hash) returntrue;
k = k->super();
} while (k != NULL); returnfalse;
}
void jfieldIDWorkaround::verify_instance_jfieldID(Klass* k, jfieldID id) {
guarantee(jfieldIDWorkaround::is_instance_jfieldID(k, id), "must be an instance field" );
uintptr_t as_uint = (uintptr_t) id;
intptr_t offset = raw_instance_offset(id); if (VerifyJNIFields) { if (is_checked_jfieldID(id)) {
guarantee(klass_hash_ok(k, id), "Bug in native code: jfieldID class must match object");
} else { #if 0 #ifndef PRODUCT if (Verbose) {
ResourceMark rm;
warning("VerifyJNIFields: unverified offset %d for %s", offset, k->external_name());
} #endif #endif
}
}
guarantee(InstanceKlass::cast(k)->contains_field_offset(offset), "Bug in native code: jfieldID offset must address interior of object");
}
// Class resolution will get the class name from the .class stream if the name is null.
TempNewSymbol class_name = name == NULL ? NULL :
SystemDictionary::class_name_symbol(name, vmSymbols::java_lang_NoClassDefFoundError(),
CHECK_NULL);
jclass result = NULL;
DT_RETURN_MARK(FindClass, jclass, (const jclass&)result);
// This should be ClassNotFoundException imo.
TempNewSymbol class_name =
SystemDictionary::class_name_symbol(name, vmSymbols::java_lang_NoClassDefFoundError(),
CHECK_NULL);
//%note jni_3
Handle protection_domain; // Find calling class
Klass* k = thread->security_get_caller_class(0); // default to the system loader when no context
Handle loader(THREAD, SystemDictionary::java_system_loader()); if (k != NULL) { // Special handling to make sure JNI_OnLoad and JNI_OnUnload are executed // in the correct class context. if (k->class_loader() == NULL &&
k->name() == vmSymbols::jdk_internal_loader_NativeLibraries()) {
JavaValue result(T_OBJECT);
JavaCalls::call_static(&result, k,
vmSymbols::getFromClass_name(),
vmSymbols::void_class_signature(),
CHECK_NULL); // When invoked from JNI_OnLoad, NativeLibraries::getFromClass returns // a non-NULL Class object. When invoked from JNI_OnUnload, // it will return NULL to indicate no context.
oop mirror = result.get_oop(); if (mirror != NULL) {
Klass* fromClass = java_lang_Class::as_Klass(mirror);
loader = Handle(THREAD, fromClass->class_loader());
protection_domain = Handle(THREAD, fromClass->protection_domain());
}
} else {
loader = Handle(THREAD, k->class_loader());
}
}
result = find_class_from_class_loader(env, class_name, true, loader,
protection_domain, true, thread);
if (log_is_enabled(Debug, class, resolve) && result != NULL) {
trace_class_resolution(java_lang_Class::as_Klass(JNIHandles::resolve_non_null(result)));
}
// Make sure class is initialized before handing id's out to methods
k1->initialize(CHECK_NULL);
Method* m = InstanceKlass::cast(k1)->method_with_idnum(slot);
ret = m==NULL? NULL : m->jmethod_id(); // return NULL if reflected method deleted return ret;
JNI_END
jfieldID ret = NULL;
DT_RETURN_MARK(FromReflectedField, jfieldID, (const jfieldID&)ret);
// field is a handle to a java.lang.reflect.Field object
oop reflected = JNIHandles::resolve_non_null(field);
oop mirror = java_lang_reflect_Field::clazz(reflected);
Klass* k1 = java_lang_Class::as_Klass(mirror); int slot = java_lang_reflect_Field::slot(reflected); int modifiers = java_lang_reflect_Field::modifiers(reflected);
// Make sure class is initialized before handing id's out to fields
k1->initialize(CHECK_NULL);
// First check if this is a static field if (modifiers & JVM_ACC_STATIC) {
intptr_t offset = InstanceKlass::cast(k1)->field_offset( slot );
JNIid* id = InstanceKlass::cast(k1)->jni_id_for(offset);
assert(id != NULL, "corrupt Field object");
debug_only(id->set_is_static_field_id();) // A jfieldID for a static field is a JNIid specifying the field holder and the offset within the Klass*
ret = jfieldIDWorkaround::to_static_jfieldID(id); return ret;
}
// The slot is the index of the field description in the field-array // The jfieldID is the offset of the field within the object // It may also have hash bits for k, if VerifyJNIFields is turned on.
intptr_t offset = InstanceKlass::cast(k1)->field_offset( slot );
assert(InstanceKlass::cast(k1)->contains_field_offset(offset), "stay within object");
ret = jfieldIDWorkaround::to_instance_jfieldID(k1, offset); return ret;
JNI_END
// JNI functions only transform a pending async exception to a synchronous // exception in ExceptionOccurred and ExceptionCheck calls, since // delivering an async exception in other places won't change the native // code's control flow and would be harmful when native code further calls // JNI functions with a pending exception. Async exception is also checked // during the call, so ExceptionOccurred/ExceptionCheck won't return // false but deliver the async exception at the very end during // state transition.
staticvoid jni_check_async_exceptions(JavaThread *thread) {
assert(thread == Thread::current(), "must be itself"); if (thread->has_async_exception_condition()) {
SafepointMechanism::process_if_requested_with_exit_check(thread, true/* check asyncs */);
}
}
if (thread->has_pending_exception()) {
Handle ex(thread, thread->pending_exception());
thread->clear_pending_exception();
jio_fprintf(defaultStream::error_stream(), "Exception "); if (thread != NULL && thread->threadObj() != NULL) {
ResourceMark rm(THREAD);
jio_fprintf(defaultStream::error_stream(), "in thread \"%s\" ", thread->name());
} if (ex->is_a(vmClasses::Throwable_klass())) {
JavaValue result(T_VOID);
JavaCalls::call_virtual(&result,
ex,
vmClasses::Throwable_klass(),
vmSymbols::printStackTrace_name(),
vmSymbols::void_method_signature(),
THREAD); // If an exception is thrown in the call it gets thrown away. Not much // we can do with it. The native code that calls this, does not check // for the exception - hence, it might still be in the thread when DestroyVM gets // called, potentially causing a few asserts to trigger - since no pending exception // is expected.
CLEAR_PENDING_EXCEPTION;
} else {
ResourceMark rm(THREAD);
jio_fprintf(defaultStream::error_stream(), ". Uncaught exception of type %s.",
ex->klass()->external_name());
}
}
// The jni code might be using this API to clear java thrown exception. // So just mark jvmti thread exception state as exception caught.
JvmtiThreadState *state = JavaThread::current()->jvmti_thread_state(); if (state != NULL && state->is_exception_detected()) {
state->set_exception_caught();
}
thread->clear_pending_exception();
//%note jni_11
Handle result_handle(thread, JNIHandles::resolve(result));
JNIHandleBlock* old_handles = thread->active_handles();
JNIHandleBlock* new_handles = old_handles->pop_frame_link(); if (new_handles != NULL) { // As a sanity check we only release the handle blocks if the pop_frame_link is not NULL. // This way code will still work if PopLocalFrame is called without a corresponding // PushLocalFrame call. Note that we set the pop_frame_link to NULL explicitly, otherwise // the release_block call will release the blocks.
thread->set_active_handles(new_handles);
old_handles->set_pop_frame_link(NULL); // clear link we won't release new_handles below
JNIHandleBlock::release_block(old_handles, thread); // may block
result = JNIHandles::make_local(thread, result_handle());
}
HOTSPOT_JNI_POPLOCALFRAME_RETURN(result); return result;
JNI_END
void push_boolean(jboolean b) { // Normalize boolean arguments from native code by converting 1-255 to JNI_TRUE and // 0 to JNI_FALSE. Boolean return values from native are normalized the same in // TemplateInterpreterGenerator::generate_result_handler_for and // SharedRuntime::generate_native_wrapper.
push_int(b == 0 ? JNI_FALSE : JNI_TRUE);
}
class JNI_ArgumentPusherVaArg : public JNI_ArgumentPusher {
va_list _ap;
void set_ap(va_list rap) {
va_copy(_ap, rap);
}
friendclass SignatureIterator; // so do_parameters_on can call do_type void do_type(BasicType type) { switch (type) { // these are coerced to int when using va_arg case T_BYTE: case T_CHAR: case T_SHORT: case T_INT: push_int(va_arg(_ap, jint)); break; case T_BOOLEAN: push_boolean((jboolean) va_arg(_ap, jint)); break;
// each of these paths is exercised by the various jck Call[Static,Nonvirtual,][Void,Int,..]Method[A,V,] tests
case T_LONG: push_long(va_arg(_ap, jlong)); break; // float is coerced to double w/ va_arg case T_FLOAT: push_float((jfloat) va_arg(_ap, jdouble)); break; case T_DOUBLE: push_double(va_arg(_ap, jdouble)); break;
case T_ARRAY: case T_OBJECT: push_object(va_arg(_ap, jobject)); break; default: ShouldNotReachHere();
}
}
friendclass SignatureIterator; // so do_parameters_on can call do_type void do_type(BasicType type) { switch (type) { case T_CHAR: push_int((_ap++)->c); break; case T_SHORT: push_int((_ap++)->s); break; case T_BYTE: push_int((_ap++)->b); break; case T_INT: push_int((_ap++)->i); break; case T_BOOLEAN: push_boolean((_ap++)->z); break; case T_LONG: push_long((_ap++)->j); break; case T_FLOAT: push_float((_ap++)->f); break; case T_DOUBLE: push_double((_ap++)->d); break; case T_ARRAY: case T_OBJECT: push_object((_ap++)->l); break; default: ShouldNotReachHere();
}
}
// Create object to hold arguments for the JavaCall, and associate it with // the jni parser
ResourceMark rm(THREAD); int number_of_parameters = method->size_of_parameters();
JavaCallArguments java_args(number_of_parameters);
assert(method->is_static(), "method should be static");
// Fill out JavaCallArguments object
args->push_arguments_on(&java_args); // Initialize result type
result->set_type(args->return_type());
// Invoke the method. Result is returned as oop.
JavaCalls::call(result, method, &java_args, CHECK);
// Convert result if (is_reference_type(result->get_type())) {
result->set_jobject(JNIHandles::make_local(THREAD, result->get_oop()));
}
}
int number_of_parameters;
Method* selected_method;
{
Method* m = Method::resolve_jmethod_id(method_id);
number_of_parameters = m->size_of_parameters();
InstanceKlass* holder = m->method_holder(); if (call_type != JNI_VIRTUAL) {
selected_method = m;
} elseif (!m->has_itable_index()) { // non-interface call -- for that little speed boost, don't handlize
debug_only(NoSafepointVerifier nosafepoint;) // jni_GetMethodID makes sure class is linked and initialized // so m should have a valid vtable index.
assert(m->valid_vtable_index(), "no valid vtable index"); int vtbl_index = m->vtable_index(); if (vtbl_index != Method::nonvirtual_vtable_index) {
selected_method = h_recv->klass()->method_at_vtable(vtbl_index);
} else { // final method
selected_method = m;
}
} else { // interface call int itbl_index = m->itable_index();
Klass* k = h_recv->klass();
selected_method = InstanceKlass::cast(k)->method_at_itable(holder, itbl_index, CHECK);
}
}
methodHandle method(THREAD, selected_method);
// Create object to hold arguments for the JavaCall, and associate it with // the jni parser
ResourceMark rm(THREAD);
JavaCallArguments java_args(number_of_parameters);
// handle arguments
assert(!method->is_static(), "method %s should not be static", method->name_and_sig_as_C_string());
java_args.push_oop(h_recv); // Push jobject handle
// Fill out JavaCallArguments object
args->push_arguments_on(&java_args); // Initialize result type
result->set_type(args->return_type());
// Invoke the method. Result is returned as oop.
JavaCalls::call(result, method, &java_args, CHECK);
// Convert result if (is_reference_type(result->get_type())) {
result->set_jobject(JNIHandles::make_local(THREAD, result->get_oop()));
}
}
static jmethodID get_method_id(JNIEnv *env, jclass clazz, constchar *name_str, constchar *sig, bool is_static, TRAPS) { // %%%% This code should probably just call into a method in the LinkResolver // // The class should have been loaded (we have an instance of the class // passed in) so the method and signature should already be in the symbol // table. If they're not there, the method doesn't exist. constchar *name_to_probe = (name_str == NULL)
? vmSymbols::object_initializer_name()->as_C_string()
: name_str;
TempNewSymbol name = SymbolTable::probe(name_to_probe, (int)strlen(name_to_probe));
TempNewSymbol signature = SymbolTable::probe(sig, (int)strlen(sig));
oop mirror = JNIHandles::resolve_non_null(clazz);
Klass* klass = java_lang_Class::as_Klass(mirror);
// Throw a NoSuchMethodError exception if we have an instance of a // primitive java.lang.Class if (java_lang_Class::is_primitive(mirror)) {
ResourceMark rm(THREAD);
THROW_MSG_0(vmSymbols::java_lang_NoSuchMethodError(), err_msg("%s%s.%s%s", is_static ? "static " : "", klass->signature_name(), name_str, sig));
}
// Make sure class is linked and initialized before handing id's out to // Method*s.
klass->initialize(CHECK_NULL);
Method* m; if (name == vmSymbols::object_initializer_name() ||
name == vmSymbols::class_initializer_name()) { // Never search superclasses for constructors if (klass->is_instance_klass()) {
m = InstanceKlass::cast(klass)->find_method(name, signature);
} else {
m = NULL;
}
} else {
m = klass->lookup_method(name, signature); if (m == NULL && klass->is_instance_klass()) {
m = InstanceKlass::cast(klass)->lookup_method_in_ordered_interfaces(name, signature);
}
} if (m == NULL || (m->is_static() != is_static)) {
ResourceMark rm(THREAD);
THROW_MSG_0(vmSymbols::java_lang_NoSuchMethodError(), err_msg("%s%s.%s%s", is_static ? "static " : "", klass->signature_name(), name_str, sig));
} return m->jmethod_id();
}
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.54Bemerkung:
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.