深入理解 JNI 字段访问:从 jfieldID 的编码到快速路径

发布时间:2026/7/11 3:08:37

深入理解 JNI 字段访问:从 jfieldID 的编码到快速路径 引言在 Java Native InterfaceJNI编程中jfieldID是一个核心概念它充当了 Java 层字段与 Native 层之间的“桥梁”。许多开发者知道通过GetFieldID获取jfieldID然后通过GetIntField等函数读取字段值但对其内部的实现机制——尤其是 HotSpot JVM 如何编码和使用jfieldID——却知之甚少。本文将通过剖析 OpenJDK 17 源码结合java.io.FileDescriptor中fd字段的实际案例深入探讨jfieldID的创建、编码、以及 JVM 提供的快速路径优化帮助读者建立从 Java 层到 Native 层的完整调用链认知。一、从实际案例出发IOUtil 中的 jfieldID 缓存在sun.nio.ch.IOUtil类的静态初始化块中有这样一段代码javastatic { jdk.internal.loader.BootLoader.loadLibrary(net); jdk.internal.loader.BootLoader.loadLibrary(nio); initIDs(); // 调用 native 方法初始化字段 ID IOV_MAX iovMax(); }对应的 native 函数Java_sun_nio_ch_IOUtil_initIDs实现如下cJNIEXPORT void JNICALL Java_sun_nio_ch_IOUtil_initIDs(JNIEnv *env, jclass clazz) { CHECK_NULL(clazz (*env)-FindClass(env, java/io/FileDescriptor)); CHECK_NULL(fd_fdID (*env)-GetFieldID(env, clazz, fd, I)); }fd_fdID是一个全局静态jfieldID变量用于缓存FileDescriptor类中名为fd、类型为int的字段 ID。后续在fdval函数中直接使用cjint fdval(JNIEnv *env, jobject fdo) { return (*env)-GetIntField(env, fdo, fd_fdID); }这种“一次查找多次复用”的模式是 JNI 编程的最佳实践因为GetFieldID需要遍历类的字段开销较大。但jfieldID到底是什么它仅仅是一个不透明的指针吗我们继续深入。二、jfieldID 的本质一个编码的整数在jni.h中jfieldID被声明为cstruct _jfieldID; typedef struct _jfieldID *jfieldID;这是一个不完整类型的前向声明实际上HotSpot JVM 并没有为实例字段的jfieldID分配真正的_jfieldID结构体。相反它被编码成一个整数值存储了字段的偏移量和元数据。在jfieldIDWorkaround.hpp中我们可以找到详细的位布局注释textBit-format of a jfieldID (most significant first): address:30 instance0:1 checked0:1 offset:30 instance1:1 checked0:1 klass:23 offset:7 instance1:1 checked1:1对于实例字段instance1jfieldID的低 2 位分别用于bit 0 (checked)标记是否启用字段校验VerifyJNIFields。bit 1 (instance)固定为 1表示这是一个实例字段。其余高 30 位或 30 位中的部分存储字段的字节偏移量offset。如果开启了校验还会将类的哈希值编码到高位中用于防止jfieldID被误用于其他类。正因为jfieldID本质上是一个整数所以我们可以直接对它进行位移操作来提取偏移量。这也是后续快速路径优化的基础。三、jfieldID 的创建jni_GetFieldID 调用链当我们调用(*env)-GetFieldID(env, clazz, fd, I)时JVM 最终会执行jni_GetFieldID函数位于jni.cpp。其核心流程如下解析类将jclass转换为Klass*。查找符号在 SymbolTable 中查找字段名和签名字符串。确保类初始化调用k-initialize()。查找字段描述符通过InstanceKlass::find_field获取fieldDescriptor其中包含字段的偏移量fd.offset()。编码生成 jfieldID调用jfieldIDWorkaround::to_instance_jfieldID(k, fd.offset())。cppJNI_ENTRY(jfieldID, jni_GetFieldID(JNIEnv *env, jclass clazz, const char *name, const char *sig)) // ... 省略查找和校验 ... ret jfieldIDWorkaround::to_instance_jfieldID(k, fd.offset()); return ret; JNI_ENDto_instance_jfieldID的实现如下cppstatic jfieldID to_instance_jfieldID(Klass* k, int offset) { intptr_t as_uint ((offset large_offset_mask) offset_shift) | instance_mask_in_place; if (VerifyJNIFields) { as_uint | encode_klass_hash(k, offset); } jfieldID result (jfieldID) as_uint; // 校验和断言 return result; }offset_shift通常是 2因为低 2 位被标志位占用。instance_mask_in_place将 bit 1 置 1。如果VerifyJNIFields开启还会通过encode_klass_hash将类的哈希值编码进高位。这样返回的jfieldID就不再是一个内存地址而是一个自描述的编码值。四、字段值的读取慢速路径与快速路径4.1 慢速路径jni_GetIntField 的通用实现当我们在fdval中调用(*env)-GetIntField(env, fdo, fd_fdID)时JVM 会通过函数指针调用相应的实现。默认情况下这个函数指针指向的是由宏DEFINE_GETFIELD展开的jni_GetIntField。该宏展开后的核心逻辑如下cppJNI_ENTRY_NO_PRESERVE(jint, jni_GetIntField(JNIEnv *env, jobject obj, jfieldID fieldID)) { oop o JNIHandles::resolve_non_null(obj); Klass* k o-klass(); int offset jfieldIDWorkaround::from_instance_jfieldID(k, fieldID); // 可选的 JVMTI 事件处理 ret o-int_field(offset); return ret; } JNI_ENDfrom_instance_jfieldID负责从jfieldID中提取偏移量cppstatic intptr_t from_instance_jfieldID(Klass* k, jfieldID id) { if (VerifyJNIFields) { verify_instance_jfieldID(k, id); // 校验类哈希 } return raw_instance_offset(id); } static intptr_t raw_instance_offset(jfieldID id) { uintptr_t result (uintptr_t) id address_shift; // address_shift 2 if (VerifyJNIFields is_checked_jfieldID(id)) { result small_offset_mask; // 7 位偏移 } return (intptr_t)result; }得到偏移量后o-int_field(offset)实际上是从对象基址加上偏移量读取 4 个字节。这个路径包含了 JNI 边界检查、JVM 状态切换ThreadInVMfromNative、JVMTI 事件等开销较大。4.2 快速路径JNI_FastGetField 生成的汇编代码HotSpot 提供了一个强大的优化机制在满足一定条件时将jni_NativeInterface结构体中的函数指针替换为手写的汇编快速路径。这是在quicken_jni_functions()中完成的cppvoid quicken_jni_functions() { if (UseFastJNIAccessors !VerifyJNIFields !CheckJNICalls) { address func JNI_FastGetField::generate_fast_get_int_field(); if (func ! (address)-1) { jni_NativeInterface.GetIntField (GetIntField_t)func; } // ... 其他类型 } }快速路径的核心生成函数是JNI_FastGetField::generate_fast_get_int_field0我们重点关注其生成的汇编逻辑以T_INT为例asm; 1. 检查安全点 mov32 rcounter, [SafepointSynchronize::safepoint_counter_addr()] testb rcounter, 1 jnz slow ; 2. 检查 JVMTI 字段访问计数 cmp32 [JvmtiExport::get_field_access_count_addr()], 0 jnz slow ; 3. 解析 jfieldID 获取偏移量右移 2 位 mov roffset, c_rarg2 ; c_rarg2 fieldID shrptr roffset, 2 ; offset fieldID 2 ; 4. 解析 jobject 为 oop call try_resolve_jobject_in_native ; 5. 直接内存读取 movl rax, [robj roffset] ; 从对象基址 偏移量取 int 值 ; 6. 再次检查安全点是否发生变化 cmp32 rcounter, [SafepointSynchronize::safepoint_counter_addr()] jne slow ret slow: jmp jni_GetIntField_addr ; 跳转到慢速路径这个快速路径的巧妙之处在于偏移量提取直接通过shrptr右移 2 位省去了 C 函数调用的开销。内存读取一条movl指令完成字段值的获取无需经过oop的成员函数。安全点检查仅检查两次安全点计数前后各一次确保在读字段期间未发生安全点。条件编译只有在UseFastJNIAccessors为 true 且未开启字段校验时才会启用保证了正确性。通过这个快速路径GetIntField的性能可以接近 C 语言直接访问结构体成员极大地提升了 JNI 字段访问的效率。五、静态字段与实例字段的区别值得特别指出的是上述编码和快速路径优化仅适用于实例字段。对于静态字段jfieldID的处理方式完全不同。在jni_GetStaticFieldID中JVM 会创建一个真实的JNIid对象定义在jniid.hpp中并将jfieldID设置为指向该对象的指针。当使用GetStaticIntField时JVM 会解引用这个指针以获取偏移量等信息。cpp// 静态字段的 jfieldID 是真实指针 JNIid* id (JNIid*)fieldID; int offset id-offset();因此实例字段的jfieldID是一个“伪指针”编码整数而静态字段的jfieldID是一个“真指针”。这也是为什么在jfieldIDWorkaround中需要通过低位标志位来区分字段类型。六、总结通过上述源码分析我们可以清晰地勾勒出jfieldID从创建到使用的完整链路Java 层静态初始化IOUtil类加载时调用initIDs()。Native 层缓存Java_sun_nio_ch_IOUtil_initIDs通过GetFieldID获取FileDescriptor.fd的jfieldID并存入全局变量fd_fdID。jfieldID 生成jni_GetFieldID查找字段偏移量并通过to_instance_jfieldID将偏移量编码为整数左移 置标志位。字段值读取慢速路径fdval调用GetIntFieldJVM 通过from_instance_jfieldID解码偏移量再通过int_field读取值。字段值读取快速路径JVM 启动时根据条件替换函数指针快速路径直接汇编实现fieldID 2 内存读取极大提升性能。这种设计体现了 HotSpot JVM 在保持 JNI 规范兼容性的同时对性能的极致追求。理解jfieldID的编码和快速路径机制不仅有助于写出更高效的 JNI 代码也能让我们对 JVM 内部实现有更深刻的认知。##源码//sun.nio.ch.IOUtil静态代码块 static { jdk.internal.loader.BootLoader.loadLibrary(net); jdk.internal.loader.BootLoader.loadLibrary(nio); initIDs(); IOV_MAX iovMax(); } //sun.nio.ch.SocketDispatcher静态代码块 static native void initIDs(); static jfieldID fd_fdID; /* for jint fd in java.io.FileDescriptor */ JNIEXPORT void JNICALL Java_sun_nio_ch_IOUtil_initIDs(JNIEnv *env, jclass clazz) { CHECK_NULL(clazz (*env)-FindClass(env, java/io/FileDescriptor)); CHECK_NULL(fd_fdID (*env)-GetFieldID(env, clazz, fd, I)); } jint fdval(JNIEnv *env, jobject fdo) { return (*env)-GetIntField(env, fdo, fd_fdID); } // Structure containing all jni functions struct JNINativeInterface_ jni_NativeInterface { NULL, NULL, NULL, NULL, jni_GetVersion, jni_DefineClass, jni_FindClass, jni_FromReflectedMethod, jni_FromReflectedField, jni_ToReflectedMethod, jni_GetSuperclass, jni_IsAssignableFrom, jni_ToReflectedField, jni_Throw, jni_ThrowNew, jni_ExceptionOccurred, jni_ExceptionDescribe, jni_ExceptionClear, jni_FatalError, jni_PushLocalFrame, jni_PopLocalFrame, jni_NewGlobalRef, jni_DeleteGlobalRef, jni_DeleteLocalRef, jni_IsSameObject, jni_NewLocalRef, jni_EnsureLocalCapacity, jni_AllocObject, jni_NewObject, jni_NewObjectV, jni_NewObjectA, jni_GetObjectClass, jni_IsInstanceOf, jni_GetMethodID, jni_CallObjectMethod, jni_CallObjectMethodV, jni_CallObjectMethodA, jni_CallBooleanMethod, jni_CallBooleanMethodV, jni_CallBooleanMethodA, jni_CallByteMethod, jni_CallByteMethodV, jni_CallByteMethodA, jni_CallCharMethod, jni_CallCharMethodV, jni_CallCharMethodA, jni_CallShortMethod, jni_CallShortMethodV, jni_CallShortMethodA, jni_CallIntMethod, jni_CallIntMethodV, jni_CallIntMethodA, jni_CallLongMethod, jni_CallLongMethodV, jni_CallLongMethodA, jni_CallFloatMethod, jni_CallFloatMethodV, jni_CallFloatMethodA, jni_CallDoubleMethod, jni_CallDoubleMethodV, jni_CallDoubleMethodA, jni_CallVoidMethod, jni_CallVoidMethodV, jni_CallVoidMethodA, jni_CallNonvirtualObjectMethod, jni_CallNonvirtualObjectMethodV, jni_CallNonvirtualObjectMethodA, jni_CallNonvirtualBooleanMethod, jni_CallNonvirtualBooleanMethodV, jni_CallNonvirtualBooleanMethodA, jni_CallNonvirtualByteMethod, jni_CallNonvirtualByteMethodV, jni_CallNonvirtualByteMethodA, jni_CallNonvirtualCharMethod, jni_CallNonvirtualCharMethodV, jni_CallNonvirtualCharMethodA, jni_CallNonvirtualShortMethod, jni_CallNonvirtualShortMethodV, jni_CallNonvirtualShortMethodA, jni_CallNonvirtualIntMethod, jni_CallNonvirtualIntMethodV, jni_CallNonvirtualIntMethodA, jni_CallNonvirtualLongMethod, jni_CallNonvirtualLongMethodV, jni_CallNonvirtualLongMethodA, jni_CallNonvirtualFloatMethod, jni_CallNonvirtualFloatMethodV, jni_CallNonvirtualFloatMethodA, jni_CallNonvirtualDoubleMethod, jni_CallNonvirtualDoubleMethodV, jni_CallNonvirtualDoubleMethodA, jni_CallNonvirtualVoidMethod, jni_CallNonvirtualVoidMethodV, jni_CallNonvirtualVoidMethodA, jni_GetFieldID, jni_GetObjectField, jni_GetBooleanField, jni_GetByteField, jni_GetCharField, jni_GetShortField, jni_GetIntField, jni_GetLongField, jni_GetFloatField, jni_GetDoubleField, jni_SetObjectField, jni_SetBooleanField, jni_SetByteField, jni_SetCharField, jni_SetShortField, jni_SetIntField, jni_SetLongField, jni_SetFloatField, jni_SetDoubleField, jni_GetStaticMethodID, jni_CallStaticObjectMethod, jni_CallStaticObjectMethodV, jni_CallStaticObjectMethodA, jni_CallStaticBooleanMethod, jni_CallStaticBooleanMethodV, jni_CallStaticBooleanMethodA, jni_CallStaticByteMethod, jni_CallStaticByteMethodV, jni_CallStaticByteMethodA, jni_CallStaticCharMethod, jni_CallStaticCharMethodV, jni_CallStaticCharMethodA, jni_CallStaticShortMethod, jni_CallStaticShortMethodV, jni_CallStaticShortMethodA, jni_CallStaticIntMethod, jni_CallStaticIntMethodV, jni_CallStaticIntMethodA, jni_CallStaticLongMethod, jni_CallStaticLongMethodV, jni_CallStaticLongMethodA, jni_CallStaticFloatMethod, jni_CallStaticFloatMethodV, jni_CallStaticFloatMethodA, jni_CallStaticDoubleMethod, jni_CallStaticDoubleMethodV, jni_CallStaticDoubleMethodA, jni_CallStaticVoidMethod, jni_CallStaticVoidMethodV, jni_CallStaticVoidMethodA, jni_GetStaticFieldID, jni_GetStaticObjectField, jni_GetStaticBooleanField, jni_GetStaticByteField, jni_GetStaticCharField, jni_GetStaticShortField, jni_GetStaticIntField, jni_GetStaticLongField, jni_GetStaticFloatField, jni_GetStaticDoubleField, jni_SetStaticObjectField, jni_SetStaticBooleanField, jni_SetStaticByteField, jni_SetStaticCharField, jni_SetStaticShortField, jni_SetStaticIntField, jni_SetStaticLongField, jni_SetStaticFloatField, jni_SetStaticDoubleField, jni_NewString, jni_GetStringLength, jni_GetStringChars, jni_ReleaseStringChars, jni_NewStringUTF, jni_GetStringUTFLength, jni_GetStringUTFChars, jni_ReleaseStringUTFChars, jni_GetArrayLength, jni_NewObjectArray, jni_GetObjectArrayElement, jni_SetObjectArrayElement, jni_NewBooleanArray, jni_NewByteArray, jni_NewCharArray, jni_NewShortArray, jni_NewIntArray, jni_NewLongArray, jni_NewFloatArray, jni_NewDoubleArray, jni_GetBooleanArrayElements, jni_GetByteArrayElements, jni_GetCharArrayElements, jni_GetShortArrayElements, jni_GetIntArrayElements, jni_GetLongArrayElements, jni_GetFloatArrayElements, jni_GetDoubleArrayElements, jni_ReleaseBooleanArrayElements, jni_ReleaseByteArrayElements, jni_ReleaseCharArrayElements, jni_ReleaseShortArrayElements, jni_ReleaseIntArrayElements, jni_ReleaseLongArrayElements, jni_ReleaseFloatArrayElements, jni_ReleaseDoubleArrayElements, jni_GetBooleanArrayRegion, jni_GetByteArrayRegion, jni_GetCharArrayRegion, jni_GetShortArrayRegion, jni_GetIntArrayRegion, jni_GetLongArrayRegion, jni_GetFloatArrayRegion, jni_GetDoubleArrayRegion, jni_SetBooleanArrayRegion, jni_SetByteArrayRegion, jni_SetCharArrayRegion, jni_SetShortArrayRegion, jni_SetIntArrayRegion, jni_SetLongArrayRegion, jni_SetFloatArrayRegion, jni_SetDoubleArrayRegion, jni_RegisterNatives, jni_UnregisterNatives, jni_MonitorEnter, jni_MonitorExit, jni_GetJavaVM, jni_GetStringRegion, jni_GetStringUTFRegion, jni_GetPrimitiveArrayCritical, jni_ReleasePrimitiveArrayCritical, jni_GetStringCritical, jni_ReleaseStringCritical, jni_NewWeakGlobalRef, jni_DeleteWeakGlobalRef, jni_ExceptionCheck, jni_NewDirectByteBuffer, jni_GetDirectBufferAddress, jni_GetDirectBufferCapacity, // New 1_6 features jni_GetObjectRefType, // Module features jni_GetModule }; void quicken_jni_functions() { // Replace GetPrimitiveField with fast versions if (UseFastJNIAccessors !VerifyJNIFields !CheckJNICalls) { address func; func JNI_FastGetField::generate_fast_get_boolean_field(); if (func ! (address)-1) { jni_NativeInterface.GetBooleanField (GetBooleanField_t)func; } func JNI_FastGetField::generate_fast_get_byte_field(); if (func ! (address)-1) { jni_NativeInterface.GetByteField (GetByteField_t)func; } func JNI_FastGetField::generate_fast_get_char_field(); if (func ! (address)-1) { jni_NativeInterface.GetCharField (GetCharField_t)func; } func JNI_FastGetField::generate_fast_get_short_field(); if (func ! (address)-1) { jni_NativeInterface.GetShortField (GetShortField_t)func; } func JNI_FastGetField::generate_fast_get_int_field(); if (func ! (address)-1) { jni_NativeInterface.GetIntField (GetIntField_t)func; } func JNI_FastGetField::generate_fast_get_long_field(); if (func ! (address)-1) { jni_NativeInterface.GetLongField (GetLongField_t)func; } func JNI_FastGetField::generate_fast_get_float_field(); if (func ! (address)-1) { jni_NativeInterface.GetFloatField (GetFloatField_t)func; } func JNI_FastGetField::generate_fast_get_double_field(); if (func ! (address)-1) { jni_NativeInterface.GetDoubleField (GetDoubleField_t)func; } } } address JNI_FastGetField::generate_fast_get_int_field() { return generate_fast_get_int_field0(T_INT); } address JNI_FastGetField::generate_fast_get_int_field0(BasicType type) { const char *name NULL; switch (type) { case T_BOOLEAN: name jni_fast_GetBooleanField; break; case T_BYTE: name jni_fast_GetByteField; break; case T_CHAR: name jni_fast_GetCharField; break; case T_SHORT: name jni_fast_GetShortField; break; case T_INT: name jni_fast_GetIntField; break; case T_LONG: name jni_fast_GetLongField; break; default: ShouldNotReachHere(); } ResourceMark rm; BufferBlob* blob BufferBlob::create(name, BUFFER_SIZE); CodeBuffer cbuf(blob); MacroAssembler* masm new MacroAssembler(cbuf); address fast_entry __ pc(); Label slow; ExternalAddress counter(SafepointSynchronize::safepoint_counter_addr()); __ mov32 (rcounter, counter); __ mov (robj, c_rarg1); __ testb (rcounter, 1); __ jcc (Assembler::notZero, slow); if (JvmtiExport::can_post_field_access()) { // Check to see if a field access watch has been set before we // take the fast path. assert_different_registers(rscratch1, robj, rcounter); // cmp32 clobbers rscratch1! __ cmp32(ExternalAddress((address) JvmtiExport::get_field_access_count_addr()), 0); __ jcc(Assembler::notZero, slow); } __ mov (roffset, c_rarg2); __ shrptr(roffset, 2); // offset // Both robj and rtmp are clobbered by try_resolve_jobject_in_native. BarrierSetAssembler* bs BarrierSet::barrier_set()-barrier_set_assembler(); bs-try_resolve_jobject_in_native(masm, /* jni_env */ c_rarg0, robj, rtmp, slow); DEBUG_ONLY(__ movl(rtmp, 0xDEADC0DE);) assert(count LIST_CAPACITY, LIST_CAPACITY too small); speculative_load_pclist[count] __ pc(); switch (type) { case T_BOOLEAN: __ movzbl (rax, Address(robj, roffset, Address::times_1)); break; case T_BYTE: __ movsbl (rax, Address(robj, roffset, Address::times_1)); break; case T_CHAR: __ movzwl (rax, Address(robj, roffset, Address::times_1)); break; case T_SHORT: __ movswl (rax, Address(robj, roffset, Address::times_1)); break; case T_INT: __ movl (rax, Address(robj, roffset, Address::times_1)); break; case T_LONG: __ movq (rax, Address(robj, roffset, Address::times_1)); break; default: ShouldNotReachHere(); } __ cmp32 (rcounter, counter); __ jcc (Assembler::notEqual, slow); __ ret (0); slowcase_entry_pclist[count] __ pc(); __ bind (slow); address slow_case_addr NULL; switch (type) { case T_BOOLEAN: slow_case_addr jni_GetBooleanField_addr(); break; case T_BYTE: slow_case_addr jni_GetByteField_addr(); break; case T_CHAR: slow_case_addr jni_GetCharField_addr(); break; case T_SHORT: slow_case_addr jni_GetShortField_addr(); break; case T_INT: slow_case_addr jni_GetIntField_addr(); break; case T_LONG: slow_case_addr jni_GetLongField_addr(); break; default: break; } // tail call __ jump (ExternalAddress(slow_case_addr)); __ flush (); return fast_entry; } address jni_GetIntField_addr() { // 慢速路径 return (address)jni_GetIntField; } #define DEFINE_GETFIELD(Return,Fieldname,Result \ , EntryProbe, ReturnProbe) \ \ DT_RETURN_MARK_DECL_FOR(Result, Get##Result##Field, Return \ , ReturnProbe); \ \ JNI_ENTRY_NO_PRESERVE(Return, jni_Get##Result##Field(JNIEnv *env, jobject obj, jfieldID fieldID)) \ \ EntryProbe; \ Return ret 0;\ DT_RETURN_MARK_FOR(Result, Get##Result##Field, Return, (const Return)ret);\ \ 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. */ \ if (JvmtiExport::should_post_field_access()) { \ o JvmtiExport::jni_GetField_probe(thread, obj, o, k, fieldID, false); \ } \ ret o-Fieldname##_field(offset); \ return ret; \ JNI_END DEFINE_GETFIELD(jboolean, bool, Boolean , HOTSPOT_JNI_GETBOOLEANFIELD_ENTRY(env, obj, (uintptr_t)fieldID), HOTSPOT_JNI_GETBOOLEANFIELD_RETURN(_ret_ref)) DEFINE_GETFIELD(jbyte, byte, Byte , HOTSPOT_JNI_GETBYTEFIELD_ENTRY(env, obj, (uintptr_t)fieldID), HOTSPOT_JNI_GETBYTEFIELD_RETURN(_ret_ref)) DEFINE_GETFIELD(jchar, char, Char , HOTSPOT_JNI_GETCHARFIELD_ENTRY(env, obj, (uintptr_t)fieldID), HOTSPOT_JNI_GETCHARFIELD_RETURN(_ret_ref)) DEFINE_GETFIELD(jshort, short, Short , HOTSPOT_JNI_GETSHORTFIELD_ENTRY(env, obj, (uintptr_t)fieldID), HOTSPOT_JNI_GETSHORTFIELD_RETURN(_ret_ref)) DEFINE_GETFIELD(jint, int, Int , HOTSPOT_JNI_GETINTFIELD_ENTRY(env, obj, (uintptr_t)fieldID), HOTSPOT_JNI_GETINTFIELD_RETURN(_ret_ref)) DEFINE_GETFIELD(jlong, long, Long , HOTSPOT_JNI_GETLONGFIELD_ENTRY(env, obj, (uintptr_t)fieldID), HOTSPOT_JNI_GETLONGFIELD_RETURN(_ret_ref)) // Float and double probes dont return value because dtrace doesnt currently support it DEFINE_GETFIELD(jfloat, float, Float , HOTSPOT_JNI_GETFLOATFIELD_ENTRY(env, obj, (uintptr_t)fieldID), HOTSPOT_JNI_GETFLOATFIELD_RETURN()) DEFINE_GETFIELD(jdouble, double, Double , HOTSPOT_JNI_GETDOUBLEFIELD_ENTRY(env, obj, (uintptr_t)fieldID), HOTSPOT_JNI_GETDOUBLEFIELD_RETURN()) //获取jfieldID Expands to: ; extern C { jint __stdcall jni_GetIntField(JNIEnv *env, jobject obj, jfieldID fieldID) { JavaThread* threadJavaThread::thread_from_jni_environment(env); ; ; ThreadInVMfromNative __tiv(thread); HandleMarkCleaner __hm(thread); JavaThread* __the_thread__ thread; os::verify_stack_alignment(); ; jint ret 0; ; oop o JNIHandles::resolve_non_null(obj); Klass* k o-klass(); int offset jfieldIDWorkaround::from_instance_jfieldID(k, fieldID); if (JvmtiExport::should_post_field_access()) { o JvmtiExport::jni_GetField_probe(thread, obj, o, k, fieldID, false); } ret o-int_field(offset); return ret; } } static intptr_t from_instance_jfieldID(Klass* k, jfieldID id) { #ifndef ASSERT // always verify in debug mode; switchable in anything else if (VerifyJNIFields) #endif // ASSERT { verify_instance_jfieldID(k, id); } return raw_instance_offset(id); } // helper routines: static bool is_checked_jfieldID(jfieldID id) { uintptr_t as_uint (uintptr_t) id; return ((as_uint checked_mask_in_place) ! 0); } static intptr_t raw_instance_offset(jfieldID id) { uintptr_t result (uintptr_t) id address_shift; if (VerifyJNIFields is_checked_jfieldID(id)) { result small_offset_mask; // cut off the hash bits } return (intptr_t)result; } static intptr_t raw_instance_offset(jfieldID id) { uintptr_t result (uintptr_t) id address_shift; if (VerifyJNIFields is_checked_jfieldID(id)) { result small_offset_mask; // cut off the hash bits } return (intptr_t)result; } //设置jfieldID JNI_ENTRY(jfieldID, jni_GetFieldID(JNIEnv *env, jclass clazz, const char *name, const char *sig)) HOTSPOT_JNI_GETFIELDID_ENTRY(env, clazz, (char *) name, (char *) sig); jfieldID ret 0; DT_RETURN_MARK(GetFieldID, jfieldID, (const jfieldID)ret); Klass* k java_lang_Class::as_Klass(JNIHandles::resolve_non_null(clazz)); // The class should have been loaded (we have an instance of the class // passed in) so the field and signature should already be in the symbol // table. If theyre not there, the field doesnt exist. TempNewSymbol fieldname SymbolTable::probe(name, (int)strlen(name)); TempNewSymbol signame SymbolTable::probe(sig, (int)strlen(sig)); if (fieldname NULL || signame NULL) { ResourceMark rm; THROW_MSG_0(vmSymbols::java_lang_NoSuchFieldError(), err_msg(%s.%s %s, k-external_name(), name, sig)); } // Make sure class is initialized before handing ids out to fields k-initialize(CHECK_NULL); fieldDescriptor fd; if (!k-is_instance_klass() || !InstanceKlass::cast(k)-find_field(fieldname, signame, false, fd)) { ResourceMark rm; THROW_MSG_0(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 static jfieldID to_instance_jfieldID(Klass* k, int offset) { intptr_t as_uint ((offset large_offset_mask) offset_shift) | instance_mask_in_place; if (VerifyJNIFields) { as_uint | encode_klass_hash(k, offset); } jfieldID result (jfieldID) as_uint; #ifndef ASSERT // always verify in debug mode; switchable in anything else if (VerifyJNIFields) #endif // ASSERT { verify_instance_jfieldID(k, result); } assert(raw_instance_offset(result) (offset large_offset_mask), extract right offset); return result; }

相关新闻