< prev index next > src/hotspot/share/prims/jni.cpp
Print this page
#include "memory/resourceArea.hpp"
#include "memory/universe.hpp"
#include "nmt/memTracker.hpp"
#include "oops/access.inline.hpp"
#include "oops/arrayOop.hpp"
+ #include "oops/flatArrayOop.inline.hpp"
+ #include "oops/inlineKlass.inline.hpp"
#include "oops/instanceKlass.inline.hpp"
#include "oops/instanceOop.hpp"
#include "oops/klass.inline.hpp"
#include "oops/markWord.hpp"
#include "oops/method.hpp"
// 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.
int 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
DT_RETURN_MARK_DECL(ToReflectedMethod, jobject
// 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.
int offset = InstanceKlass::cast(k1)->field_offset( slot );
+ bool is_flat = InstanceKlass::cast(k1)->field_is_flat(slot);
assert(InstanceKlass::cast(k1)->contains_field_offset(offset), "stay within object");
! ret = jfieldIDWorkaround::to_instance_jfieldID(k1, offset, is_flat);
return ret;
JNI_END
DT_RETURN_MARK_DECL(ToReflectedMethod, jobject
DT_RETURN_MARK(ToReflectedMethod, jobject, (const jobject&)ret);
methodHandle m (THREAD, Method::resolve_jmethod_id(method_id));
assert(m->is_static() == (isStatic != 0), "jni_ToReflectedMethod access flags doesn't match");
oop reflection_method;
! if (m->is_initializer()) {
reflection_method = Reflection::new_constructor(m, CHECK_NULL);
} else {
reflection_method = Reflection::new_method(m, false, CHECK_NULL);
}
ret = JNIHandles::make_local(THREAD, reflection_method);
DT_RETURN_MARK(ToReflectedMethod, jobject, (const jobject&)ret);
methodHandle m (THREAD, Method::resolve_jmethod_id(method_id));
assert(m->is_static() == (isStatic != 0), "jni_ToReflectedMethod access flags doesn't match");
oop reflection_method;
! if (m->is_object_constructor()) {
reflection_method = Reflection::new_constructor(m, CHECK_NULL);
} else {
reflection_method = Reflection::new_method(m, false, CHECK_NULL);
}
ret = JNIHandles::make_local(THREAD, reflection_method);
// 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();
}
}
public:
// 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();
}
}
public:
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();
}
}
public:
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:
+ case T_PRIMITIVE_OBJECT: push_object((_ap++)->l); break;
default: ShouldNotReachHere();
}
}
public:
HOTSPOT_JNI_ALLOCOBJECT_ENTRY(env, clazz);
jobject ret = nullptr;
DT_RETURN_MARK(AllocObject, jobject, (const jobject&)ret);
! instanceOop i = InstanceKlass::allocate_instance(JNIHandles::resolve_non_null(clazz), CHECK_NULL);
ret = JNIHandles::make_local(THREAD, i);
return ret;
JNI_END
DT_RETURN_MARK_DECL(NewObjectA, jobject
HOTSPOT_JNI_ALLOCOBJECT_ENTRY(env, clazz);
jobject ret = nullptr;
DT_RETURN_MARK(AllocObject, jobject, (const jobject&)ret);
! oop clazzoop = JNIHandles::resolve_non_null(clazz);
+ Klass* k = java_lang_Class::as_Klass(clazzoop);
+ if (k == nullptr || k->is_inline_klass()) {
+ ResourceMark rm(THREAD);
+ THROW_(vmSymbols::java_lang_InstantiationException(), nullptr);
+ }
+ instanceOop i = InstanceKlass::allocate_instance(clazzoop, CHECK_NULL);
ret = JNIHandles::make_local(THREAD, i);
return ret;
JNI_END
DT_RETURN_MARK_DECL(NewObjectA, jobject
HOTSPOT_JNI_NEWOBJECTA_ENTRY(env, clazz, (uintptr_t) methodID);
jobject obj = nullptr;
DT_RETURN_MARK(NewObjectA, jobject, (const jobject&)obj);
! instanceOop i = InstanceKlass::allocate_instance(JNIHandles::resolve_non_null(clazz), CHECK_NULL);
obj = JNIHandles::make_local(THREAD, i);
JavaValue jvalue(T_VOID);
JNI_ArgumentPusherArray ap(methodID, args);
jni_invoke_nonstatic(env, &jvalue, obj, JNI_NONVIRTUAL, methodID, &ap, CHECK_NULL);
return obj;
! JNI_END
DT_RETURN_MARK_DECL(NewObjectV, jobject
, HOTSPOT_JNI_NEWOBJECTV_RETURN(_ret_ref));
HOTSPOT_JNI_NEWOBJECTA_ENTRY(env, clazz, (uintptr_t) methodID);
jobject obj = nullptr;
DT_RETURN_MARK(NewObjectA, jobject, (const jobject&)obj);
! oop clazzoop = JNIHandles::resolve_non_null(clazz);
+ Klass* k = java_lang_Class::as_Klass(clazzoop);
+ if (k == nullptr) {
+ ResourceMark rm(THREAD);
+ THROW_(vmSymbols::java_lang_InstantiationException(), nullptr);
+ }
+
+ instanceOop i = InstanceKlass::allocate_instance(clazzoop, CHECK_NULL);
obj = JNIHandles::make_local(THREAD, i);
JavaValue jvalue(T_VOID);
JNI_ArgumentPusherArray ap(methodID, args);
jni_invoke_nonstatic(env, &jvalue, obj, JNI_NONVIRTUAL, methodID, &ap, CHECK_NULL);
+
return obj;
! JNI_END
DT_RETURN_MARK_DECL(NewObjectV, jobject
, HOTSPOT_JNI_NEWOBJECTV_RETURN(_ret_ref));
HOTSPOT_JNI_NEWOBJECTV_ENTRY(env, clazz, (uintptr_t) methodID);
jobject obj = nullptr;
DT_RETURN_MARK(NewObjectV, jobject, (const jobject&)obj);
! instanceOop i = InstanceKlass::allocate_instance(JNIHandles::resolve_non_null(clazz), CHECK_NULL);
obj = JNIHandles::make_local(THREAD, i);
JavaValue jvalue(T_VOID);
JNI_ArgumentPusherVaArg ap(methodID, args);
jni_invoke_nonstatic(env, &jvalue, obj, JNI_NONVIRTUAL, methodID, &ap, CHECK_NULL);
return obj;
JNI_END
DT_RETURN_MARK_DECL(NewObject, jobject
HOTSPOT_JNI_NEWOBJECTV_ENTRY(env, clazz, (uintptr_t) methodID);
jobject obj = nullptr;
DT_RETURN_MARK(NewObjectV, jobject, (const jobject&)obj);
! oop clazzoop = JNIHandles::resolve_non_null(clazz);
+ Klass* k = java_lang_Class::as_Klass(clazzoop);
+ if (k == nullptr) {
+ ResourceMark rm(THREAD);
+ THROW_(vmSymbols::java_lang_InstantiationException(), nullptr);
+ }
+
+ instanceOop i = InstanceKlass::allocate_instance(clazzoop, CHECK_NULL);
obj = JNIHandles::make_local(THREAD, i);
JavaValue jvalue(T_VOID);
JNI_ArgumentPusherVaArg ap(methodID, args);
jni_invoke_nonstatic(env, &jvalue, obj, JNI_NONVIRTUAL, methodID, &ap, CHECK_NULL);
+
return obj;
JNI_END
DT_RETURN_MARK_DECL(NewObject, jobject
HOTSPOT_JNI_NEWOBJECT_ENTRY(env, clazz, (uintptr_t) methodID);
jobject obj = nullptr;
DT_RETURN_MARK(NewObject, jobject, (const jobject&)obj);
! instanceOop i = InstanceKlass::allocate_instance(JNIHandles::resolve_non_null(clazz), CHECK_NULL);
obj = JNIHandles::make_local(THREAD, i);
va_list args;
va_start(args, methodID);
JavaValue jvalue(T_VOID);
JNI_ArgumentPusherVaArg ap(methodID, args);
jni_invoke_nonstatic(env, &jvalue, obj, JNI_NONVIRTUAL, methodID, &ap, CHECK_NULL);
va_end(args);
return obj;
JNI_END
JNI_ENTRY(jclass, jni_GetObjectClass(JNIEnv *env, jobject obj))
HOTSPOT_JNI_NEWOBJECT_ENTRY(env, clazz, (uintptr_t) methodID);
jobject obj = nullptr;
DT_RETURN_MARK(NewObject, jobject, (const jobject&)obj);
! oop clazzoop = JNIHandles::resolve_non_null(clazz);
+ Klass* k = java_lang_Class::as_Klass(clazzoop);
+ if (k == nullptr) {
+ ResourceMark rm(THREAD);
+ THROW_(vmSymbols::java_lang_InstantiationException(), nullptr);
+ }
+
+ instanceOop i = InstanceKlass::allocate_instance(clazzoop, CHECK_NULL);
obj = JNIHandles::make_local(THREAD, i);
va_list args;
va_start(args, methodID);
JavaValue jvalue(T_VOID);
JNI_ArgumentPusherVaArg ap(methodID, args);
jni_invoke_nonstatic(env, &jvalue, obj, JNI_NONVIRTUAL, methodID, &ap, CHECK_NULL);
va_end(args);
+
return obj;
JNI_END
JNI_ENTRY(jclass, jni_GetObjectClass(JNIEnv *env, jobject obj))
THROW_MSG_NULL(vmSymbols::java_lang_NoSuchFieldError(), err_msg("%s.%s %s", k->external_name(), name, sig));
}
// A jfieldID for a non-static field is simply the offset of the field within the instanceOop
// It may also have hash bits for k, if VerifyJNIFields is turned on.
! ret = jfieldIDWorkaround::to_instance_jfieldID(k, fd.offset());
return ret;
JNI_END
JNI_ENTRY(jobject, jni_GetObjectField(JNIEnv *env, jobject obj, jfieldID fieldID))
HOTSPOT_JNI_GETOBJECTFIELD_ENTRY(env, obj, (uintptr_t) fieldID);
oop o = JNIHandles::resolve_non_null(obj);
Klass* k = o->klass();
int offset = jfieldIDWorkaround::from_instance_jfieldID(k, fieldID);
// Keep JVMTI addition small and only check enabled flag here.
// jni_GetField_probe() assumes that is okay to create handles.
if (JvmtiExport::should_post_field_access()) {
o = JvmtiExport::jni_GetField_probe(thread, obj, o, k, fieldID, false);
}
! oop loaded_obj = HeapAccess<ON_UNKNOWN_OOP_REF>::oop_load_at(o, offset);
! jobject ret = JNIHandles::make_local(THREAD, loaded_obj);
HOTSPOT_JNI_GETOBJECTFIELD_RETURN(ret);
return ret;
JNI_END
THROW_MSG_NULL(vmSymbols::java_lang_NoSuchFieldError(), err_msg("%s.%s %s", k->external_name(), name, sig));
}
// A jfieldID for a non-static field is simply the offset of the field within the instanceOop
// It may also have hash bits for k, if VerifyJNIFields is turned on.
! ret = jfieldIDWorkaround::to_instance_jfieldID(k, fd.offset(), fd.is_flat());
return ret;
JNI_END
JNI_ENTRY(jobject, jni_GetObjectField(JNIEnv *env, jobject obj, jfieldID fieldID))
HOTSPOT_JNI_GETOBJECTFIELD_ENTRY(env, obj, (uintptr_t) fieldID);
oop o = JNIHandles::resolve_non_null(obj);
Klass* k = o->klass();
int offset = jfieldIDWorkaround::from_instance_jfieldID(k, fieldID);
+ oop res = nullptr;
// Keep JVMTI addition small and only check enabled flag here.
// jni_GetField_probe() assumes that is okay to create handles.
if (JvmtiExport::should_post_field_access()) {
o = JvmtiExport::jni_GetField_probe(thread, obj, o, k, fieldID, false);
}
! if (!jfieldIDWorkaround::is_flat_jfieldID(fieldID)) {
! res = HeapAccess<ON_UNKNOWN_OOP_REF>::oop_load_at(o, offset);
+ } else {
+ assert(k->is_instance_klass(), "Only instance can have flat fields");
+ InstanceKlass* ik = InstanceKlass::cast(k);
+ fieldDescriptor fd;
+ ik->find_field_from_offset(offset, false, &fd); // performance bottleneck
+ InstanceKlass* holder = fd.field_holder();
+ InlineLayoutInfo* li = holder->inline_layout_info_adr(fd.index());
+ InlineKlass* field_vklass = li->klass();
+ res = field_vklass->read_flat_field(o, ik->field_offset(fd.index()), li->kind(), CHECK_NULL);
+ }
+ jobject ret = JNIHandles::make_local(THREAD, res);
HOTSPOT_JNI_GETOBJECTFIELD_RETURN(ret);
return ret;
JNI_END
if (JvmtiExport::should_post_field_modification()) {
jvalue field_value;
field_value.l = value;
o = JvmtiExport::jni_SetField_probe(thread, obj, o, k, fieldID, false, JVM_SIGNATURE_CLASS, (jvalue *)&field_value);
}
! HeapAccess<ON_UNKNOWN_OOP_REF>::oop_store_at(o, offset, JNIHandles::resolve(value));
HOTSPOT_JNI_SETOBJECTFIELD_RETURN();
JNI_END
// TODO: make this a template
if (JvmtiExport::should_post_field_modification()) {
jvalue field_value;
field_value.l = value;
o = JvmtiExport::jni_SetField_probe(thread, obj, o, k, fieldID, false, JVM_SIGNATURE_CLASS, (jvalue *)&field_value);
}
! if (!jfieldIDWorkaround::is_flat_jfieldID(fieldID)) {
+ HeapAccess<ON_UNKNOWN_OOP_REF>::oop_store_at(o, offset, JNIHandles::resolve(value));
+ } else {
+ assert(k->is_instance_klass(), "Only instances can have flat fields");
+ InstanceKlass* ik = InstanceKlass::cast(k);
+ fieldDescriptor fd;
+ ik->find_field_from_offset(offset, false, &fd);
+ InstanceKlass* holder = fd.field_holder();
+ InlineLayoutInfo* li = holder->inline_layout_info_adr(fd.index());
+ InlineKlass* vklass = li->klass();
+ oop v = JNIHandles::resolve_non_null(value);
+ vklass->write_flat_field(o, offset, v, fd.is_null_free_inline_type(), li->kind(), CHECK);
+ }
HOTSPOT_JNI_SETOBJECTFIELD_RETURN();
JNI_END
// TODO: make this a template
JNI_ENTRY(jobject, jni_GetObjectArrayElement(JNIEnv *env, jobjectArray array, jsize index))
HOTSPOT_JNI_GETOBJECTARRAYELEMENT_ENTRY(env, array, index);
jobject ret = nullptr;
DT_RETURN_MARK(GetObjectArrayElement, jobject, (const jobject&)ret);
! objArrayOop a = objArrayOop(JNIHandles::resolve_non_null(array));
! if (a->is_within_bounds(index)) {
! ret = JNIHandles::make_local(THREAD, a->obj_at(index));
! return ret;
} else {
ResourceMark rm(THREAD);
stringStream ss;
! ss.print("Index %d out of bounds for length %d", index, a->length());
THROW_MSG_NULL(vmSymbols::java_lang_ArrayIndexOutOfBoundsException(), ss.as_string());
}
JNI_END
DT_VOID_RETURN_MARK_DECL(SetObjectArrayElement
, HOTSPOT_JNI_SETOBJECTARRAYELEMENT_RETURN());
JNI_ENTRY(void, jni_SetObjectArrayElement(JNIEnv *env, jobjectArray array, jsize index, jobject value))
HOTSPOT_JNI_SETOBJECTARRAYELEMENT_ENTRY(env, array, index, value);
DT_VOID_RETURN_MARK(SetObjectArrayElement);
! objArrayOop a = objArrayOop(JNIHandles::resolve_non_null(array));
! oop v = JNIHandles::resolve(value);
! if (a->is_within_bounds(index)) {
! if (v == nullptr || v->is_a(ObjArrayKlass::cast(a->klass())->element_klass())) {
! a->obj_at_put(index, v);
! } else {
! ResourceMark rm(THREAD);
! stringStream ss;
! Klass *bottom_kl = ObjArrayKlass::cast(a->klass())->bottom_klass();
! ss.print("type mismatch: can not store %s to %s[%d]",
! v->klass()->external_name(),
! bottom_kl->is_typeArray_klass() ? type2name_tab[ArrayKlass::cast(bottom_kl)->element_type()] : bottom_kl->external_name(),
! index);
! for (int dims = ArrayKlass::cast(a->klass())->dimension(); dims > 1; --dims) {
! ss.print("[]");
! }
! THROW_MSG(vmSymbols::java_lang_ArrayStoreException(), ss.as_string());
! }
! } else {
! ResourceMark rm(THREAD);
! stringStream ss;
! ss.print("Index %d out of bounds for length %d", index, a->length());
! THROW_MSG(vmSymbols::java_lang_ArrayIndexOutOfBoundsException(), ss.as_string());
! }
JNI_END
#define DEFINE_NEWSCALARARRAY(Return,Allocator,Result \
JNI_ENTRY(jobject, jni_GetObjectArrayElement(JNIEnv *env, jobjectArray array, jsize index))
HOTSPOT_JNI_GETOBJECTARRAYELEMENT_ENTRY(env, array, index);
jobject ret = nullptr;
DT_RETURN_MARK(GetObjectArrayElement, jobject, (const jobject&)ret);
! oop res = nullptr;
! arrayOop arr((arrayOop)JNIHandles::resolve_non_null(array));
! if (arr->is_within_bounds(index)) {
! if (arr->is_flatArray()) {
+ flatArrayOop a = flatArrayOop(JNIHandles::resolve_non_null(array));
+ flatArrayHandle vah(thread, a);
+ res = flatArrayOopDesc::value_alloc_copy_from_index(vah, index, CHECK_NULL);
+ assert(res != nullptr, "Must be set in one of two paths above");
+ } else {
+ assert(arr->is_objArray(), "If not a valueArray. must be an objArray");
+ objArrayOop a = objArrayOop(JNIHandles::resolve_non_null(array));
+ res = a->obj_at(index);
+ }
} else {
ResourceMark rm(THREAD);
stringStream ss;
! ss.print("Index %d out of bounds for length %d", index,arr->length());
THROW_MSG_NULL(vmSymbols::java_lang_ArrayIndexOutOfBoundsException(), ss.as_string());
}
+ ret = JNIHandles::make_local(THREAD, res);
+ return ret;
JNI_END
DT_VOID_RETURN_MARK_DECL(SetObjectArrayElement
, HOTSPOT_JNI_SETOBJECTARRAYELEMENT_RETURN());
JNI_ENTRY(void, jni_SetObjectArrayElement(JNIEnv *env, jobjectArray array, jsize index, jobject value))
HOTSPOT_JNI_SETOBJECTARRAYELEMENT_ENTRY(env, array, index, value);
DT_VOID_RETURN_MARK(SetObjectArrayElement);
! bool oob = false;
! int length = -1;
! oop res = nullptr;
! arrayOop arr((arrayOop)JNIHandles::resolve_non_null(array));
! if (arr->is_within_bounds(index)) {
! if (arr->is_flatArray()) {
! flatArrayOop a = flatArrayOop(JNIHandles::resolve_non_null(array));
! oop v = JNIHandles::resolve(value);
! FlatArrayKlass* vaklass = FlatArrayKlass::cast(a->klass());
! InlineKlass* element_vklass = vaklass->element_klass();
! if (v != nullptr && v->is_a(element_vklass)) {
! a->value_copy_to_index(v, index, LayoutKind::PAYLOAD); // Temporary hack for the transition
! } else {
! ResourceMark rm(THREAD);
! stringStream ss;
! Klass *kl = FlatArrayKlass::cast(a->klass());
! ss.print("type mismatch: can not store %s to %s[%d]",
! v->klass()->external_name(),
! kl->external_name(),
! index);
! for (int dims = ArrayKlass::cast(a->klass())->dimension(); dims > 1; --dims) {
! ss.print("[]");
! }
! THROW_MSG(vmSymbols::java_lang_ArrayStoreException(), ss.as_string());
+ }
+ } else {
+ assert(arr->is_objArray(), "If not a valueArray. must be an objArray");
+ objArrayOop a = objArrayOop(JNIHandles::resolve_non_null(array));
+ oop v = JNIHandles::resolve(value);
+ if (v == nullptr || v->is_a(ObjArrayKlass::cast(a->klass())->element_klass())) {
+ a->obj_at_put(index, v);
+ } else {
+ ResourceMark rm(THREAD);
+ stringStream ss;
+ Klass *bottom_kl = ObjArrayKlass::cast(a->klass())->bottom_klass();
+ ss.print("type mismatch: can not store %s to %s[%d]",
+ v->klass()->external_name(),
+ bottom_kl->is_typeArray_klass() ? type2name_tab[ArrayKlass::cast(bottom_kl)->element_type()] : bottom_kl->external_name(),
+ index);
+ for (int dims = ArrayKlass::cast(a->klass())->dimension(); dims > 1; --dims) {
+ ss.print("[]");
+ }
+ THROW_MSG(vmSymbols::java_lang_ArrayStoreException(), ss.as_string());
+ }
+ }
+ } else {
+ ResourceMark rm(THREAD);
+ stringStream ss;
+ ss.print("Index %d out of bounds for length %d", index, arr->length());
+ THROW_MSG(vmSymbols::java_lang_ArrayIndexOutOfBoundsException(), ss.as_string());
+ }
JNI_END
#define DEFINE_NEWSCALARARRAY(Return,Allocator,Result \
< prev index next >