目录
一、InterpreterGenerator::generate_native_entry
2、set_native_function和clear_native_function
3、jni_RegisterNatives和jni_UnregisterNatives
1、signature_handler和set_signature_handler
2、 SignatureHandlerLibrary::add
在之前的一篇《Hotspot 字节码执行与栈顶缓存实现 源码解析》中我们讲解了用来生成不同类型的MethodKind的方法的调用Stub的 AbstractInterpreterGenerator::generate_method_entry方法的实现,通过分析其中的InterpreterGenerator::generate_normal_entry的实现弄明白了普通Java方法是如何被解释执行的,如何在解释执行的过程中实现栈顶缓存的,本篇博客探讨generate_method_entry调用的用来生成本地方法调用Stub的InterpreterGenerator::generate_native_entry方法的实现。
一、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
__ and