Hotspot 本地方法绑定与执行 源码解析

   目录

一、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

     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完成的。

二、Method native_function

1、定义

      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判断是否绑定了本地代码。

2、set_native_function和clear_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的调用链如下:

3、jni_RegisterNatives和jni_UnregisterNatives

     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

 4、NativeLookup::lookup

       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

1、signature_handler和set_signature_handler

      Method中关于signature_handler的方法只有两个,如下图:

另一个set_signature_handler方法的实现很简单,如下:

 

 其调用链如下:

除SignatureHandlerLibrary::add方法外,另外三个方法都是set NULL。 

signature_handler方法的调用链如下:

2、 SignatureHandlerLibrary::add

       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<uint64_t>(32, true);
  _handlers     = new(ResourceObj::C_HEAP, mtCode)GrowableArray<address>(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

      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;
}
发布了117 篇原创文章 · 获赞 8 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_31865983/article/details/103332863