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

来源:互联网 发布:兼职 大数据 英文 翻译 编辑:程序博客网 时间:2024/04/30 10:08

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。
原创粉丝点击