目录
一、InterpreterGenerator::generate_native_entry
二、Method native_function
1、定义
2、set_native_function和clear_native_function
3、jni_RegisterNatives和jni_UnregisterNatives
4、NativeLookup::lookup
三、Method signature_handler
1、signature_handler和set_signature_handler
2、 SignatureHandlerLibrary::add
四、Interpreter::result_handler
在之前的一篇《Hotspot 字节码执行与栈顶缓存实现 源码解析》中我们讲解了用来生成不同类型的MethodKind的方法的调用Stub的 AbstractInterpreterGenerator::generate_method_entry方法的实现,通过分析其中的InterpreterGenerator::generate_normal_entry的实现弄明白了普通Java方法是如何被解释执行的,如何在解释执行的过程中实现栈顶缓存的,本篇博客探讨generate_method_entry调用的用来生成本地方法调用Stub的InterpreterGenerator::generate_native_entry方法的实现。
InterpreterGenerator::generate_native_entry用来生成本地方法的调用Stub,进入此方法前的栈帧结构可以参考《Hotspot 方法调用之StubGenerator 源码解析》中generate_call_stub方法的分析。generate_native_entry方法的源码说明如下:
//用于生成一个从解释器中调用本地方法的调用地址,为了能够执行本地方法需要适当调整栈帧
address InterpreterGenerator::generate_native_entry(bool synchronized) {
// determine code generation flags
bool inc_counter = UseCompiler || CountCompiledCalls;
// rbx: Method*
// r13: sender sp
address entry_point = __ pc();
//rbx保存的是Method的地址,根据偏移计算constMethod属性的地址,access_flags属性的地址
const Address constMethod (rbx, Method::const_offset());
const Address access_flags (rbx, Method::access_flags_offset());
//根据ConstMethod的地址和size_of_parameters属性的偏移计算该属性的地址
const Address size_of_parameters(rcx, ConstMethod::
size_of_parameters_offset());
//获取方法参数的个数
__ movptr(rcx, constMethod);
__ load_unsigned_short(rcx, size_of_parameters);
// rbx: Method*
// rcx: size of parameters
// r13: sender sp
//将栈顶的方法调用返回地址pop掉,放入rax中
__ pop(rax); // get return address
//根据rsp的地址和参数个数计算起始参数的地址
__ lea(r14, Address(rsp, rcx, Address::times_8, -wordSize));
// 为本地调用初始化两个4字节的数据,其中一个保存result_handler,一个保存oop temp
__ push((int) NULL_WORD);
__ push((int) NULL_WORD);
//初始化一个新的栈帧
generate_fixed_frame(true);
//将当前线程的do_not_unlock_if_synchronized置为true
const Address do_not_unlock_if_synchronized(r15_thread,
in_bytes(JavaThread::do_not_unlock_if_synchronized_offset()));
__ movbool(do_not_unlock_if_synchronized, true);
Label invocation_counter_overflow;
//如果开启方法编译
if (inc_counter) {
//增加方法调用计数
generate_counter_incr(&invocation_counter_overflow, NULL, NULL);
}
Label continue_after_compile;
__ bind(continue_after_compile);
//检查shadow_pages,跟异常处理有关
bang_stack_shadow_pages(true);
// 将do_not_unlock_if_synchronized置为false
__ movbool(do_not_unlock_if_synchronized, false);
// 必须在invocation_counter之后执行
if (synchronized) {
//获取方法的锁
lock_method();
} else {
}
// start execution
/发布JVMTI事件
__ notify_method_entry();
// work registers
const Register method = rbx;
const Register t = r11;
//从栈帧中将Method的地址放入rbx中
__ get_method(method);
__ movptr(t, Address(method, Method::const_offset()));
//将方法参数个数放入t中
__ load_unsigned_short(t, Address(t, ConstMethod::size_of_parameters_offset()));
//shl为逻辑左移指定位的指令
__ shll(t, Interpreter::logStackElementSize);
//重新计算栈顶指针的位置
__ subptr(rsp, t);
__ subptr(rsp, frame::arg_reg_save_area_bytes); // windows
__ andptr(rsp, -16); // must be 16 byte boundary (see amd64 ABI)
// get signature handler
{
Label L;
//校验method的signature_handler属性非空,该属性只有本地方法有
__ movptr(t, Address(method, Method::signature_handler_offset()));
__ testptr(t, t);
__ jcc(Assembler::notZero, L);
//调用prepare_native_call确保本地方法已绑定且安装了方法签名解析代码
__ call_VM(noreg,
CAST_FROM_FN_PTR(address,
InterpreterRuntime::prepare_native_call),
method);
__ get_method(method);
//将signature_handler放入t中
__ movptr(t, Address(method, Method::signature_handler_offset()));
__ bind(L);
}
//86_x64下的from的实现就是返回r14的地址,即起始参数的地址
assert(InterpreterRuntime::SignatureHandlerGenerator::from() == r14,
"adjust this code");
assert(InterpreterRuntime::SignatureHandlerGenerator::to() == rsp,
"adjust this code");
assert(InterpreterRuntime::SignatureHandlerGenerator::temp() == rscratch1,
"adjust this code");
//调用signature_handler,解析方法参数,整个过程一般不会改变rbx,但是慢速处理时可能导致gc,所以调用完成最好重新获取Method
__ call(t);
__ get_method(method);
//将rax中的result handler方法栈帧中,result handler是执行signature_handler返回的,根据方法签名的返回类型获取的
__ movptr(Address(rbp,
(frame::interpreter_frame_result_handler_offset) * wordSize),
rax);
// pass mirror handle if static call
{
Label L;
const int mirror_offset = in_bytes(Klass::java_mirror_offset());
__ movl(t, Address(method, Method::access_flags_offset()));
//判断是否是static本地方法,如果不是则跳转到L
__ testl(t, JVM_ACC_STATIC);
__ jcc(Assembler::zero, L);
//如果是static本地方法
__ movptr(t, Address(method, Method::const_offset()));
__ movptr(t, Address(t, ConstMethod::constants_offset()));
__ movptr(t, Address(t, ConstantPool::pool_holder_offset_in_bytes()));
//获取mirror klass的地址
__ movptr(t, Address(t, mirror_offset));
// 将mirror klass拷贝到栈帧中
__ movptr(Address(rbp, frame::interpreter_frame_oop_temp_offset * wordSize),
t);
// 将mirror klass拷贝到c_rarg1中作为静态方法调用的第一个入参
__ lea(c_rarg1,
Address(rbp, frame::interpreter_frame_oop_temp_offset * wordSize));
__ bind(L);
}
// get native function entry point
{
Label L;
//获取native_function的地址拷贝到rax中
__ movptr(rax, Address(method, Method::native_function_offset()));
ExternalAddress unsatisfied(SharedRuntime::native_method_throw_unsatisfied_link_error_entry());
__ movptr(rscratch2, unsatisfied.addr());
//判断rax中的地址是否是native_method_throw_unsatisfied_link_error_entry的地址,如果是说明本地方法未绑定
__ cmpptr(rax, rscratch2);
//如果不等于,即已绑定,则跳转到L
__ jcc(Assembler::notEqual, L);
//调用InterpreterRuntime::prepare_native_call重试,完成方法绑定
__ call_VM(noreg,
CAST_FROM_FN_PTR(address,
InterpreterRuntime::prepare_native_call),
method);
__ get_method(method);
//获取native_function的地址拷贝到rax中
__ movptr(rax, Address(method, Method::native_function_offset()));
__ bind(L);
}
// 将当前线程的JNIEnv属性放入c_rarg0
__ lea(c_rarg0, Address(r15_thread, JavaThread::jni_environment_offset()));
//保存上一次调用的Java栈帧的rsp,rbp
__ set_last_Java_frame(rsp, rbp, (address) __ pc());
// 将线程的状态改成_thread_in_native
__ movl(Address(r15_thread, JavaThread::thread_state_offset()),
_thread_in_native);
//调用本地方法
__ call(rax);
// result potentially in rax or xmm0
// 方法调用结束校验或者恢复CPU控制状态
__ restore_cpu_control_state_after_jni();
//保存rax寄存中方法调用的结果
__ push(dtos);
__ push(ltos);
//改变线程的状态到_thread_in_native_trans
__ movl(Address(r15_thread, JavaThread::thread_state_offset()),
_thread_in_native_trans);
//如果是多处理器系统
if (os::is_MP()) {
//如果使用内存栅栏
if (UseMembar) {
//强制内存修改同步到多个处理器,在下面的读开始之前
__ membar(Assembler::Membar_mask_bits(
Assembler::LoadLoad | Assembler::LoadStore |
Assembler::StoreLoad | Assembler::StoreStore));
} else {
__ serialize_memory(r15_thread, rscratch2);
}
}
// check for safepoint operation in progress and/or pending suspend requests
{
Label Continue;
//判断安全点的状态是否是_not_synchronized
__ cmp32(ExternalAddress(SafepointSynchronize::address_of_state()),
SafepointSynchronize::_not_synchronized);
Label L;
//如果不等于,即处于安全点则跳转到L
__ jcc(Assembler::notEqual, L);
__ cmpl(Address(r15_thread, JavaThread::suspend_flags_offset()), 0);
//判断当前线程的suspend_flags是否等于0,如果等于则跳转到Continue
__ jcc(Assembler::equal, Continue);
__ bind(L);
//安全点检查相关操作
__ mov(c_rarg0, r15_thread);
__ mov(r12, rsp); // remember sp (can only use r12 if not using call_VM)
__ subptr(rsp, frame::arg_reg_save_area_bytes); // windows
__ andptr(rsp, -16); // align stack as required by ABI
__ call(RuntimeAddress(CAST_FROM_FN_PTR(address, JavaThread::check_special_condition_for_native_trans)));
__ mov(rsp, r12); // restore sp
__ reinit_heapbase();
__ bind(Continue);
}
//线程状态调整成_thread_in_Java
__ movl(Address(r15_thread, JavaThread::thread_state_offset()), _thread_in_Java);
//恢复最近一次的Java栈帧
__ reset_last_Java_frame(r15_thread, true);
//重置当前线程的JNIHandleBlock
__ movptr(t, Address(r15_thread, JavaThread::active_handles_offset()));
__ movl(Address(t, JNIHandleBlock::top_offset_in_bytes()), (int32_t)NULL_WORD);
// If result is an oop unbox and store it in frame where gc will see it
// and result handler will pick it up
{
Label no_oop;
__ lea(t, ExternalAddress(AbstractInterpreter::result_handler(T_OBJECT)));
//比较方法的结果处理程序result_handler是否是T_OBJECT类型的
__ cmpptr(t, Address(rbp, frame::interpreter_frame_result_handler_offset*wordSize));
//如果不是则跳转到no_oop
__ jcc(Assembler::notEqual, no_oop);
//如果是,先把栈顶的long类型的数据即oop地址pop出来放到rax中
__ pop(ltos);
//oop校验相关,做必要的垃圾回收处理
__ resolve_jobject(rax /* value */,
r15_thread /* thread */,
t /* tmp */);
//将rax中的oop保存了到栈帧中
__ movptr(Address(rbp, frame::interpreter_frame_oop_temp_offset*wordSize), rax);
//重新将rax中的oop放到栈顶
__ push(ltos);
__ bind(no_oop);
}
{
Label no_reguard;
//判断当前线程的_stack_guard_state属性是否是stack_guard_yellow_disabled,即是否发生了stack overflow
__ cmpl(Address(r15_thread, JavaThread::stack_guard_state_offset()),
JavaThread::stack_guard_yellow_disabled);
//如果不等于,即没有发生stack overflow,则跳转到no_reguard
__ jcc(Assembler::notEqual, no_reguard);
//如果等,即发生stack overflow,则调用reguard_yellow_pages做必要的处理
__ pusha(); // XXX only save smashed registers
__ mov(r12, rsp); // remember sp (can only use r12 if not using call_VM)
__ subptr(rsp, frame::arg_reg_save_area_bytes); // windows
__ andptr(rsp, -16); // align stack as required by ABI
__ call(RuntimeAddress(CAST_FROM_FN_PTR(address, SharedRuntime::reguard_yellow_pages)));
__ mov(rsp, r12); // restore sp
__ popa(); // XXX only restore smashed registers
__ reinit_heapbase();
__ bind(no_reguard);
}
//重新加载Method
__ get_method(method);
// restore r13 to have legal interpreter frame, i.e., bci == 0 <=>
// r13 == code_base()
__ movptr(r13, Address(method, Method::const_offset())); // get ConstMethod*
__ lea(r13, Address(r13, ConstMethod::codes_offset())); // get codebase
//处理异常
{
Label L;
//判断当前线程的_pending_exception属性是否为空,即是否发生了异常
__ cmpptr(Address(r15_thread, Thread::pending_exception_offset()), (int32_t) NULL_WORD);
//如果为空,即没有异常,跳转到L
__ jcc(Assembler::zero, L);
/调用throw_pending_exception方法抛出异常
__ MacroAssembler::call_VM(noreg,
CAST_FROM_FN_PTR(address,
InterpreterRuntime::throw_pending_exception));
__ should_not_reach_here();
__ bind(L);
}
// do unlocking if necessary
{
Label L;
__ movl(t, Address(method, Method::access_flags_offset()));
//判断目标方法是否是SYNCHRONIZED方法,如果是则需要解锁,如果不是则跳转到L
__ testl(t, JVM_ACC_SYNCHRONIZED);
__ jcc(Assembler::zero, L);
// the code below should be shared with interpreter macro
// assembler implementation
{
Label unlock;
//获取偏向锁BasicObjectLock的地址
const Address monitor(rbp,
(intptr_t)(frame::interpreter_frame_initial_sp_offset *
wordSize - sizeof(BasicObjectLock)));
// 将monitor的地址放入c_rarg1
__ lea(c_rarg1, monitor); // address of first monitor
//获取偏向锁的_obj属性的地址
__ movptr(t, Address(c_rarg1, BasicObjectLock::obj_offset_in_bytes()));
//判断_obj属性是否为空,如果不为空即未解锁,跳转到unlock完成解锁
__ testptr(t, t);
__ jcc(Assembler::notZero, unlock);
//如果已解锁,说明锁的状态有问题,抛出异常
__ MacroAssembler::call_VM(noreg,
CAST_FROM_FN_PTR(address,
InterpreterRuntime::throw_illegal_monitor_state_exception));
__ should_not_reach_here();
__ bind(unlock);
__ unlock_object(c_rarg1);
}
__ bind(L);
}
// 发布jvmti事件
__ notify_method_exit(vtos, InterpreterMacroAssembler::NotifyJVMTI);
//将栈顶的代表方法调用结果的数据pop到rax中
__ pop(ltos);
__ pop(dtos);
//获取result_handler的地址
__ movptr(t, Address(rbp,
(frame::interpreter_frame_result_handler_offset) * wordSize));
//调用result_handler处理方法调用结果
__ call(t);
// 获取sender sp,开始恢复到上一个Java栈帧
__ movptr(t, Address(rbp,
frame::interpreter_frame_sender_sp_offset *
wordSize)); // get sender sp
__ leave(); // remove frame anchor
__ pop(rdi); // get return address
__ mov(rsp, t); // set sp to sender sp
__ jmp(rdi);
if (inc_counter) {
//如果调用计数超过阈值会跳转到此行代码,触发方法的编译
__ bind(invocation_counter_overflow);
generate_counter_overflow(&continue_after_compile);
}
return entry_point;
}
IRT_ENTRY(void, InterpreterRuntime::prepare_native_call(JavaThread* thread, Method* method))
methodHandle m(thread, method);
//校验是本地方法
assert(m->is_native(), "sanity check");
bool in_base_library;
//如果尚未绑定,则完成方法绑定
if (!m->has_native_function()) {
NativeLookup::lookup(m, in_base_library, CHECK);
}
//安装方法签名解析代码(signature handler)
SignatureHandlerLibrary::add(m);
//解释器调用本地方法前会先检查signature handle是否存在,因此应该最后处理,多处理器下可以看到非null的signature handler
IRT_END
对比generate_normal_entry方法的实现,两者实现热点代码编译的方法是一样的,不同的是跳转的分支和跳转逻辑稍微有差异,因为本地方法只有普通方法调用触发的编译,没有循环次数超过阈值触发的栈上替换编译,另外本地方法执行也不需要开启profile收集性能信息。参考上一篇《Hotspot 方法编译之CompileBroker 源码解析》中CompileBroker::compile_method方法的分析可知,本地方法不需要走C1/C2编译器编译,因为本地方法的实现本身就已经是经过GCC等编译器优化过的代码,本地方法的编译只是生成了一个更高效的适配器而已,参考下面的AdapterHandlerLibrary::create_native_wrapper方法的实现。
另外因为本地方法的执行跟普通Java方法不同,generate_native_entry在真正调用本地方法对应的本地代码前会通过InterpreterRuntime::prepare_native_call方法完成本地代码和signature_handler的安装,然后调用signature_handler完成本地方法调用的参数解析等工作。本地代码调用完成,最终通过result_handler将本地方法执行的结果转换成Java代码可以执行使用的,result_handler是signature_handler解析方法签名获取方法调用结果类型后,根据结果类型设置匹配的result_handler,参考下面的SignatureHandlerGenerator的实现分析。
注意generate_native_entry生成的本地方法的调用Stub跟generate_normal_entry生成的普通Java方法调用Stub一样最终都是赋值给Method的_from_interpreted_entry属性,即通过Java代码通过解释器调用的,跟普通Java方法触发热点编译,生成的编译代码的入口地址完全是两码事。本地方法调用普通的Java方法或者本地方法都是通过JNI完成,调用JVM自身的类的相关方法是通过正常的C/C++方法调用完成,JNI调用就是通过JavaCalls::call_helper 到StubRoutines::call_stub到执行generate_normal_entry生成的调用Stub完成的。
native_function是只有本地方法的Method才有的属性,为了节省内存,没有单独定义属性,而是直接用Method对应内存下面的8个字节来表示,存储的就是本地方法对应的本地代码的调用地址,上一节中 InterpreterGenerator::generate_native_entry方法就是通过call指令调用native_function保存的调用地址完成本地方法调用的。与之类似还有一个保存解析方法签名的handle的地址的signature_handler,参考Method的内存结构示意图如下:
获取native_function和signature_handler的地址的方法的实现(参考method.hpp中)如下图:
注意这里的this+1,因为this的类型是Method,所以加1并不是加一个字节而是增加一个Method对应的字节数,即获取Method对应内存区域的下一个字节的地址;第二个native_function_addr() + 1,因为 native_function_addr()返回的就是一个指针类型的数据,所以这里的加1是增加指针对应的字节数,64位下是8字节。
Method中跟native_function相关的方法如下图:
重点关注set_native_function和clear_native_function方法的实现,critical_native_function是按照critical模式查找匹配的本地方法实现,has_native_function判断是否绑定了本地代码。
set_native_function用于设置native_function属性,即完成本地方法与本地代码实现的绑定,clear_native_function用于将native_function属性重置为native_method_throw_unsatisfied_link_error_entry,其源码说明如下:
void Method::set_native_function(address function, bool post_event_flag) {
//校验function不为空且不能是MethodHandle相关方法
assert(function != NULL, "use clear_native_function to unregister natives");
assert(!is_method_handle_intrinsic() || function == SharedRuntime::native_method_throw_unsatisfied_link_error_entry(), "");
address* native_function = native_function_addr();
// 获取native_function保存的地址
address current = *native_function;
//如果与native_function已保存的地址一样则返回
if (current == function) return;
//如果不一样
if (post_event_flag && JvmtiExport::should_post_native_method_bind() &&
function != NULL) {
assert(function !=
SharedRuntime::native_method_throw_unsatisfied_link_error_entry(),
"post_event_flag mis-match");
//JVMTI发布本地方法绑定事件
JvmtiExport::post_native_method_bind(this, &function);
}
//修改native_function保存的地址
*native_function = function;
//code非空时则将其标记为非最新的
nmethod* nm = code(); // Put it into local variable to guard against concurrent updates
if (nm != NULL) {
nm->make_not_entrant();
}
}
void Method::clear_native_function() {
// Note: is_method_handle_intrinsic() is allowed here.
//将native_function恢复成初始的native_method_throw_unsatisfied_link_error_entry
set_native_function(
SharedRuntime::native_method_throw_unsatisfied_link_error_entry(),
!native_bind_event_is_interesting);
//清除nmethod
clear_code();
}
set_native_function调用链如下:
其中link_method和clear_native_function的实现都是将native_function设置native_method_throw_unsatisfied_link_error_entry,如下图:
clear_native_function的调用链如下:
jni_RegisterNatives用于注册本地方法的实现,即完成本地方法与本地实现代码的绑定,jni_UnregisterNatives是完成某个类的所有本地方法与本地实现代码的解绑,具体用法参考《Hotspot JNI调用详解》,其源码说明如下:
JNI_ENTRY(jint, jni_RegisterNatives(JNIEnv *env, jclass clazz,
const JNINativeMethod *methods,
jint nMethods))
JNIWrapper("RegisterNatives");
// DTRACE_PROBE4和DT_RETURN_MARK都是打印DTRACE日志
DTRACE_PROBE4(hotspot_jni, RegisterNatives__entry, env, clazz, methods, nMethods);
jint ret = 0;
DT_RETURN_MARK(RegisterNatives, jint, (const jint&)ret);
//获取方法所属的klass
KlassHandle h_k(thread, java_lang_Class::as_Klass(JNIHandles::resolve_non_null(clazz)));
//遍历JNINativeMethod数组
for (int index = 0; index < nMethods; index++) {
const char* meth_name = methods[index].name;
const char* meth_sig = methods[index].signature;
int meth_name_len = (int)strlen(meth_name);
//获取方法名和方法签名在符号表中对应的符号,因为指定方法已经完成加载所以这两个符号都已经存在
TempNewSymbol name = SymbolTable::probe(meth_name, meth_name_len);
TempNewSymbol signature = SymbolTable::probe(meth_sig, (int)strlen(meth_sig));
//这两个符号引用任意一个为空则抛出异常
if (name == NULL || signature == NULL) {
ResourceMark rm;
stringStream st;
st.print("Method %s.%s%s not found", h_k()->external_name(), meth_name, meth_sig);
// Must return negative value on failure
THROW_MSG_(vmSymbols::java_lang_NoSuchMethodError(), st.as_string(), -1);
}
//设置native_function,fnPtr属性就是对应本地方法的入口地址
bool res = register_native(h_k, name, signature,
(address) methods[index].fnPtr, THREAD);
//如果register_native执行失败
if (!res) {
ret = -1;
break;
}
}
return ret;
JNI_END
static bool register_native(KlassHandle k, Symbol* name, Symbol* signature, address entry, TRAPS) {
//根据方法名和方法签名查找对应的Method
Method* method = k()->lookup_method(name, signature);
//查找失败抛出异常
if (method == NULL) {
ResourceMark rm;
stringStream st;
st.print("Method %s name or signature does not match",
Method::name_and_sig_as_C_string(k(), name, signature));
THROW_MSG_(vmSymbols::java_lang_NoSuchMethodError(), st.as_string(), false);
}
//如果不是本地方法抛出异常
if (!method->is_native()) {
// trying to register to a non-native method, see if a JVM TI agent has added prefix(es)
method = find_prefixed_native(k, name, signature, THREAD);
if (method == NULL) {
ResourceMark rm;
stringStream st;
st.print("Method %s is not declared as native",
Method::name_and_sig_as_C_string(k(), name, signature));
THROW_MSG_(vmSymbols::java_lang_NoSuchMethodError(), st.as_string(), false);
}
}
//如果方法调用地址不为空,则设置set_native_function
if (entry != NULL) {
method->set_native_function(entry,
Method::native_bind_event_is_interesting);
} else {
//如果为空,则将其重置成初始状态
method->clear_native_function();
}
//打印日志
if (PrintJNIResolving) {
ResourceMark rm(THREAD);
tty->print_cr("[Registering JNI native method %s.%s]",
method->method_holder()->external_name(),
method->name()->as_C_string());
}
return true;
}
JNI_ENTRY(jint, jni_UnregisterNatives(JNIEnv *env, jclass clazz))
JNIWrapper("UnregisterNatives");
DTRACE_PROBE2(hotspot_jni, UnregisterNatives__entry, env, clazz);
//获取clazz对应的klass
Klass* k = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(clazz));
if (k->oop_is_instance()) {
//遍历所有的方法
for (int index = 0; index < InstanceKlass::cast(k)->methods()->length(); index++) {
Method* m = InstanceKlass::cast(k)->methods()->at(index);
//找到本地方法,将其native_function和signature_handler重置
if (m->is_native()) {
m->clear_native_function();
m->set_signature_handler(NULL);
}
}
}
DTRACE_PROBE1(hotspot_jni, UnregisterNatives__return, 0);
return 0;
JNI_END
jni_RegisterNatives用于程序显示的完成本地方法与本地实现的绑定,NativeLookup::lookup则用于在遵循javah头文件的命名规范下本地方法与本地实现的绑定,是一种被动的绑定,在本地方法第一次执行的时候才会完成绑定。其源码实现如下:
address NativeLookup::lookup(methodHandle method, bool& in_base_library, TRAPS) {
//如果没有绑定本地代码实现
if (!method->has_native_function()) {
//查找该方法对应的本地代码实现
address entry = lookup_base(method, in_base_library, CHECK_NULL);
//设置native_function
method->set_native_function(entry,
Method::native_bind_event_is_interesting);
//打印日志
if (PrintJNIResolving) {
ResourceMark rm(THREAD);
tty->print_cr("[Dynamic-linking native method %s.%s ... JNI]",
method->method_holder()->external_name(),
method->name()->as_C_string());
}
}
return method->native_function();
}
address NativeLookup::lookup_base(methodHandle method, bool& in_base_library, TRAPS) {
address entry = NULL;
ResourceMark rm(THREAD);
//先按照标准的命名规范去查找匹配的本地方法实现
entry = lookup_entry(method, in_base_library, THREAD);
if (entry != NULL) return entry;
//按非标准的命名方式重试
entry = lookup_entry_prefixed(method, in_base_library, THREAD);
if (entry != NULL) return entry;
//查找失败抛出异常
THROW_MSG_0(vmSymbols::java_lang_UnsatisfiedLinkError(),
method->name_and_sig_as_C_string());
}
address NativeLookup::lookup_entry(methodHandle method, bool& in_base_library, TRAPS) {
address entry = NULL;
in_base_library = false;
//获取jni方法名,由Java_klass_name_method_name拼出来的
char* pure_name = pure_jni_name(method);
//获取方法参数个数
int args_size = 1 // JNIEnv
+ (method->is_static() ? 1 : 0) // class for static methods
+ method->size_of_parameters(); // actual parameters
//分别在不同命名规范下尝试查找匹配的本地方法实现,通常是使用第一种格式
// 1) Try JNI short style
entry = lookup_style(method, pure_name, "", args_size, true, in_base_library, CHECK_NULL);
if (entry != NULL) return entry;
//计算比较长的jni name
char* long_name = long_jni_name(method);
// 2) Try JNI long style
entry = lookup_style(method, pure_name, long_name, args_size, true, in_base_library, CHECK_NULL);
if (entry != NULL) return entry;
// 3) Try JNI short style without os prefix/suffix
entry = lookup_style(method, pure_name, "", args_size, false, in_base_library, CHECK_NULL);
if (entry != NULL) return entry;
// 4) Try JNI long style without os prefix/suffix
entry = lookup_style(method, pure_name, long_name, args_size, false, in_base_library, CHECK_NULL);
return entry; // NULL indicates not found
}
//获取正常的JNI方法的方法名,javah生成的方法中通常会是Java_jni_klassname_methodname的形式,
//最终生成的dll文件中会去掉中间jni,即Java_klassname_methodname
char* NativeLookup::pure_jni_name(methodHandle method) {
stringStream st;
// Prefix
st.print("Java_");
// Klass name
mangle_name_on(&st, method->klass_name());
st.print("_");
// Method name
mangle_name_on(&st, method->name());
return st.as_string();
}
char* NativeLookup::long_jni_name(methodHandle method) {
//将方法的入参拼起来作为JNI 方法名的一部分
stringStream st;
Symbol* signature = method->signature();
st.print("__");
// find ')'
int end;
for (end = 0; end < signature->utf8_length() && signature->byte_at(end) != ')'; end++);
// skip first '('
mangle_name_on(&st, signature, 1, end);
return st.as_string();
}
address NativeLookup::lookup_style(methodHandle method, char* pure_name, const char* long_name, int args_size, bool os_style, bool& in_base_library, TRAPS) {
address entry;
//计算完整的本地方法的实现方法的方法名
stringStream st;
//linux下前缀和后缀都没有
if (os_style) os::print_jni_name_prefix_on(&st, args_size);
st.print_raw(pure_name);
st.print_raw(long_name);
if (os_style) os::print_jni_name_suffix_on(&st, args_size);
char* jni_name = st.as_string();
//如果这个方法对应的类的classLoader为null,即属于bootstrap类加载器加载的类
Handle loader(THREAD, method->method_holder()->class_loader());
if (loader.is_null()) {
//先在特殊的本地方法中查找
entry = lookup_special_native(jni_name);
if (entry == NULL) {
//不是特殊本地方法,在本地java库文件中查找对应的实现
entry = (address) os::dll_lookup(os::native_java_library(), jni_name);
}
//查找成功
if (entry != NULL) {
in_base_library = true;
return entry;
}
}
//否则调用ClassLoader.findNative方法查找
KlassHandle klass (THREAD, SystemDictionary::ClassLoader_klass());
Handle name_arg = java_lang_String::create_from_str(jni_name, CHECK_NULL);
JavaValue result(T_LONG);
JavaCalls::call_static(&result,
klass,
vmSymbols::findNative_name(),
vmSymbols::classloader_string_long_signature(),
// Arguments
loader,
name_arg,
CHECK_NULL);
entry = (address) (intptr_t) result.get_jlong();
if (entry == NULL) {
//在Java agent的依赖库文件中查找
AgentLibrary* agent;
for (agent = Arguments::agents(); agent != NULL; agent = agent->next()) {
entry = (address) os::dll_lookup(agent->os_lib(), jni_name);
if (entry != NULL) {
return entry;
}
}
}
return entry;
}
//所有特殊的本地方法实现
static JNINativeMethod lookup_special_native_methods[] = {
{ CC"Java_sun_misc_Unsafe_registerNatives", NULL, FN_PTR(JVM_RegisterUnsafeMethods) },
{ CC"Java_java_lang_invoke_MethodHandleNatives_registerNatives", NULL, FN_PTR(JVM_RegisterMethodHandleMethods) },
{ CC"Java_sun_misc_Perf_registerNatives", NULL, FN_PTR(JVM_RegisterPerfMethods) },
{ CC"Java_sun_hotspot_WhiteBox_registerNatives", NULL, FN_PTR(JVM_RegisterWhiteBoxMethods) },
};
static address lookup_special_native(char* jni_name) {
int count = sizeof(lookup_special_native_methods) / sizeof(JNINativeMethod);
for (int i = 0; i < count; i++) {
//特殊的Java本地方法
if (strstr(jni_name, lookup_special_native_methods[i].name) != NULL) {
return CAST_FROM_FN_PTR(address, lookup_special_native_methods[i].fnPtr);
}
}
return NULL;
}
NativeLookup::lookup的调用链如下:
最后一个base_library_lookup是按照类名,方法名和方法签名查找对应本地方法的本地实现,用于初始化基本类型的转换方法,参考initialize_converter_functions方法的实现。
Method中关于signature_handler的方法只有两个,如下图:
另一个set_signature_handler方法的实现很简单,如下:
其调用链如下:
除SignatureHandlerLibrary::add方法外,另外三个方法都是set NULL。
signature_handler方法的调用链如下:
SignatureHandlerLibrary::add方法用于生成根据方法签名解析方法参数的解析器,当方法参数个数小于Fingerprinter::max_size_of_parameters时可以生成并使用根据方法签名定制的快速的解析器,否则使用通用的相对较慢的解析器。
void SignatureHandlerLibrary::add(methodHandle method) {
//如果没有对应的signature_handler
if (method->signature_handler() == NULL) {
// use slow signature handler if we can't do better
int handler_index = -1;
//UseFastSignatureHandlers默认为true,表示是否使用定制的fast SignatureHandlers
//这里判断能否使用定制的fast SignatureHandlers
if (UseFastSignatureHandlers && method->size_of_parameters() <= Fingerprinter::max_size_of_parameters) {
//获取锁
MutexLocker mu(SignatureHandlerLibrary_lock);
// 确保SignatureHandlerLibrary的基础数据结构已初始化完成
initialize();
//获取这个方法的指纹,然后在_fingerprints中查找是否存在相同的
//_fingerprints是一个自动增长的uint64_t类型的数组
uint64_t fingerprint = Fingerprinter(method).fingerprint();
handler_index = _fingerprints->find(fingerprint);
//如果没有找到相同的
if (handler_index < 0) {
ResourceMark rm;
//计算用于保存SignatureHandler的起始地址,_buffer是一个用于临时保存SignatureHandler的BufferBlob的起始地址
ptrdiff_t align_offset = (address)
round_to((intptr_t)_buffer, CodeEntryAlignment) - (address)_buffer;
CodeBuffer buffer((address)(_buffer + align_offset),
SignatureHandlerLibrary::buffer_size - align_offset);
//generate方法的实现与CPU架构相关,参考interpreterRT_x86_64.cpp中的实现
InterpreterRuntime::SignatureHandlerGenerator(method, &buffer).generate(fingerprint);
//将buffer临时保存的代码拷贝到handler_blob中
address handler = set_handler(&buffer);
//handler为空,即新申请handler_blob失败,内存不足
if (handler == NULL) {
// use slow signature handler
} else {
//拷贝成功
if (PrintSignatureHandlers) {
//打印调试日志
tty->cr();
tty->print_cr("argument handler #%d for: %s %s (fingerprint = " UINT64_FORMAT ", %d bytes generated)",
_handlers->length(),
(method->is_static() ? "static" : "receiver"),
method->name_and_sig_as_C_string(),
fingerprint,
buffer.insts_size());
Disassembler::decode(handler, handler + buffer.insts_size());
}
// 将新生成的handler插入到_handlers数组,对应的方法指纹插入到_fingerprints
_fingerprints->append(fingerprint);
_handlers->append(handler);
//校验_fingerprints和_handlers的长度一致,即两个都添加成功
assert(_fingerprints->length() == _handlers->length(), "sanity check");
//更新handler_index
handler_index = _fingerprints->length() - 1;
}
}
// 内存不足导致分配新的handle失败
if (handler_index < 0) {
// 使用通用的 slow SignatureHandler
method->set_signature_handler(Interpreter::slow_signature_handler());
} else {
//分配或者查找成功,设置到方法属性中
method->set_signature_handler(_handlers->at(handler_index));
}
} else {
//如果不支持使用fast SignatureHandler,设置成slow_signature_handler
CHECK_UNHANDLED_OOPS_ONLY(Thread::current()->clear_unhandled_oops());
method->set_signature_handler(Interpreter::slow_signature_handler());
}
}
}
address SignatureHandlerLibrary::set_handler_blob() {
BufferBlob* handler_blob = BufferBlob::create("native signature handlers", blob_size);
if (handler_blob == NULL) {
return NULL;
}
address handler = handler_blob->code_begin();
_handler_blob = handler_blob;
_handler = handler;
return handler;
}
void SignatureHandlerLibrary::initialize() {
if (_fingerprints != NULL) {
return;
}
if (set_handler_blob() == NULL) {
vm_exit_out_of_memory(blob_size, OOM_MALLOC_ERROR, "native signature handlers");
}
BufferBlob* bb = BufferBlob::create("Signature Handler Temp Buffer",
SignatureHandlerLibrary::buffer_size);
_buffer = bb->code_begin();
_fingerprints = new(ResourceObj::C_HEAP, mtCode)GrowableArray(32, true);
_handlers = new(ResourceObj::C_HEAP, mtCode)GrowableArray(32, true);
}
address SignatureHandlerLibrary::set_handler(CodeBuffer* buffer) {
//_handler是下一个待分配的handler的地址
address handler = _handler;
int insts_size = buffer->pure_insts_size();
//_handler_blob是实际保存生成的handler的地方,如果_handler_blob剩余空间不足则重新申请一个新的
if (handler + insts_size > _handler_blob->code_end()) {
// get a new handler blob
handler = set_handler_blob();
}
//如果handler不为空,即有足够的内存
if (handler != NULL) {
//将buffer中的数据拷贝到handler中
memcpy(handler, buffer->insts_begin(), insts_size);
//linux下空实现
pd_set_handler(handler);
ICache::invalidate_range(handler, insts_size);
//重置_handler属性
_handler = handler + insts_size;
}
return handler;
}
SignatureHandlerGenerator::generate方法的实现如下,其中iterate的实现可以参考《Hotspot 方法调用之JavaCalls 源码解析》中SignatureIterator类的实现,我们关注最后返回的result_handler。
Interpreter::result_handler方法返回特定类型的返回值的处理Stub,其实现如下:
static address result_handler(BasicType type) {
return _native_abi_to_tosca[BasicType_as_index(type)];
}
_native_abi_to_tosca是AbstractInterpreter定义的一个保存所有类型的返回值的处理Stub静态数组,该数组的初始化在TemplateInterpreterGenerator::generate_all方法中,如下图:
memset是将is_generated数组元素全部初始化成0,然后逐一生成所有类型的result handler,generate_result_handler_for方法的源码说明如下:
address TemplateInterpreterGenerator::generate_result_handler_for(
BasicType type) {
address entry = __ pc();
switch (type) {
case T_BOOLEAN: __ c2bool(rax); break;
case T_CHAR : __ movzwl(rax, rax); break;
case T_BYTE : __ sign_extend_byte(rax); break;
case T_SHORT : __ sign_extend_short(rax); break; //上面四种类型都是将其做适当的扩容
case T_INT : /* nothing to do */ break;
case T_LONG : /* nothing to do */ break;
case T_VOID : /* nothing to do */ break;
case T_FLOAT : /* nothing to do */ break;
case T_DOUBLE : /* nothing to do */ break; //剩余的几种类型可以通过汇编指令直接处理,无需特殊处理
case T_OBJECT :
// 将rax的对象指针放入栈帧中并校验是否非空
__ movptr(rax, Address(rbp, frame::interpreter_frame_oop_temp_offset*wordSize));
__ verify_oop(rax);
break;
default : ShouldNotReachHere();
}
__ ret(0); // return from result handler
return entry;
}