java JNI 实现原理 (五) JNI方法解释调用

Hotspot主要有两种解释器,而下面我们主要讨论的是 Template Intepreter也叫asm interprete解释器, 文章下面的介绍基本都是基于template解释器

我们举一个invokespecial的例子,下面是templateTable方法解释invokespecial的代码

void TemplateTable::invokespecial(int byte_no) {
  transition(vtos, vtos);
  assert(byte_no == f1_byte, "use this argument");
  prepare_invoke(rbx, noreg, byte_no);
  // do the call
  __ verify_oop(rbx);
  __ profile_call(rax);
  __ jump_from_interpreted(rbx, rax);
}

函数prepare_invoke

函数prepare_invoke的层级调用关系

TemplateTable::prepare_invoke

         -> TemplateTable::load_invoke_cp_cache_entry

                   -> TemplateTable::resolve_cache_and_index

在函数中resolve_cache_and_index可以看到

1. 首先先检查constantpoolcache,是否将方法指针保存到到线程的constantpoolcache里,如果有在方法里会使用jcc跳转到Label resolved去,而Lable resolved 在方法第一次运行结束后bind到函数的末尾。

2. 如果cache里没有那么会尝试用interpreterRuntime:resolve_invoke去找到正确的method, 并保存到constant pool cache 里

  case Bytecodes::_invokevirtual:
  case Bytecodes::_invokespecial:
  case Bytecodes::_invokestatic:
  case Bytecodes::_invokeinterface:
    entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_invoke);
    break;

而函数
interpreterRuntime:resolve_invoke
         -->LinkResolver::resolve_invoke
                -->LinkResolver::resolve_special_call
                       -->LinkResolver::linktime_resolve_special_method
                               -->LinkResolver::resolve_method
不论什么调用方式,最后都会调用LinkResolver::resolve_method 找到真实的调用方法,通过runtime_resolve_special_method把method指针作为methodhandle存放到CallInfo 中传回InterperterRuntime::resolve_invoke中,同时在CallInfo::set_common当设置-Xcomp情况下,决定是否需要编译方法。

我们可以看到方法prepare_invoke,已经找到了methodoop指针并且存放到寄存器rbx中

函数jump_from_interpreted

void InterpreterMacroAssembler::jump_from_interpreted(Register method, Register temp) {
  prepare_to_jump_from_interpreted();

  if (JvmtiExport::can_post_interpreter_events()) {
    Label run_compiled_code;
    // JVMTI events, such as single-stepping, are implemented partly by avoiding running
    // compiled code in threads for which the event is enabled.  Check here for
    // interp_only_mode if these events CAN be enabled.
    get_thread(temp);
    // interp_only is an int, on little endian it is sufficient to test the byte only
    // Is a cmpl faster (ce
    cmpb(Address(temp, JavaThread::interp_only_mode_offset()), 0);
    jcc(Assembler::zero, run_compiled_code);
    jmp(Address(method, methodOopDesc::interpreter_entry_offset()));
    bind(run_compiled_code);
  }

  jmp(Address(method, methodOopDesc::from_interpreted_offset()));

}
我们看到跳转到了methodoop中的_from_interpreted_entry,也就是在前面的博客里(java JNI (四) 初始化JNI方法)说的generate_native_entry 中


在这篇博客并没有太多的涉及到native方法的调用,而是asm解释器在解释一个方法的时候如何link到所对应method,并且找到处理method的entry。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值