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
    __ and
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值