JavaCalls::call代码阅读

     JavaCalls::call为hotspot调用java方法的实现之一。其调用os::os_exception_wrapper(call_helper, result, &method, args, THREAD);这个还是比较好看懂,通过传入call_helper函数指针,在call_helper上面封装了异常的处理,典型的回调函数用法。call_helper的实现里面的具体调用java函数的方法相对难看明白,下面进行进一步分析。

   ....

   //函数的具体调用

  { JavaCallWrapper link(method, receiver, result, CHECK);
    { HandleMark hm(thread);  // HandleMark used by HandleMarkCleaner

      StubRoutines::call_stub()(
        (address)&link,
        // (intptr_t*)&(result->_value), // see NOTE above (compiler problem)
        result_val_address,          // see NOTE above (compiler problem)
        result_type,
        method(),
        entry_point,
        args->parameters(),
        args->size_of_parameters(),
        CHECK
      );

      result = link.result();  // circumvent MS C++ 5.0 compiler bug (result is clobbered across call)
      // Preserve oop return value across possible gc points
      if (oop_result_flag) {
        thread->set_vm_result((oop) result->get_jobject());
      }
    }

    上面代码中StubRoutines::call_stub()返回的是一个函数指针,在执行上面的call_stub()时,会先将参数先压入堆栈。

    这个函数指针指向什么地方呢,这是和机器类型有关的,以X86-32为例,看stubGenerator_x86_32.cpp里面

StubGenerator::generate_call_stub。返回的是__pc()的值,这个值其实是内存的的一个动态生态的机器码的一个位置。

    address generate_call_stub(address& return_address) {
           StubCodeMark mark(this, "StubRoutines", "call_stub");
           address start = __ pc(); //注意,这是返回的指针值,下面还继续生成机器码,也就是说在上面的javaCall

                                                 //会调用下面产生的机器码,这些才是真正调用java方法的内容。

           bool  sse_save = false;
    const Address rsp_after_call(rbp, -4 * wordSize); // same as in generate_catch_exception()!
    const int     locals_count_in_bytes  (4*wordSize);
    const Address mxcsr_save    (rbp, -4 * wordSize);
    const Address saved_rbx     (rbp, -3 * wordSize);
    const Address saved_rsi     (rbp, -2 * wordSize);
    const Address saved_rdi     (rbp, -1 * wordSize);
    const Address result        (rbp,  3 * wordSize);
    const Address result_type   (rbp,  4 * wordSize);
    const Address method        (rbp,  5 * wordSize);
    const Address entry_point   (rbp,  6 * wordSize);
    const Address parameters    (rbp,  7 * wordSize);
    const Address parameter_size(rbp,  8 * wordSize);
    const Address thread        (rbp,  9 * wordSize); // same as in generate_catch_exception()!
    sse_save =  UseSSE > 0;

    //上面为对调用压入的堆栈进行的处理,将具体的值赋给寄存器

    //下面就是残端代码,主要是产生机器码,用类似汇编语言的格式产生

   // stub code
    __ enter();
    __ movl(rcx, parameter_size);              // parameter counter
    __ shll(rcx, Interpreter::logStackElementSize()); // convert parameter count to bytes
    __ addl(rcx, locals_count_in_bytes);       // reserve space for register saves
    __ subl(rsp, rcx);
    __ andl(rsp, -(StackAlignmentInBytes));    // Align stack

    .....

   采用类的方法,模拟汇编语言产生机器码还是很体现了大牛们的水平。

   汇编调用java方法的具体代码

       // call Java function
    __ BIND(parameters_done);
    __ movl(rbx, method);              // get methodOop
    __ movl(rax, entry_point);         // get entry_point
    __ movl(rsi, rsp);                 // set sender sp
    BLOCK_COMMENT("call Java function");
    __ call(rax);

   上面就将cpu控制转向了entry_point,这正是java方法的入口。

   这个entry_point从何而来,从method->from_interpreted_entry(),从methodOopDesc::link_method中获取address entry = Interpreter::entry_for_method(h_method),也就是说如果不用jit的,直接调用解析器的入口,由解释器再进行操作。

你可能感兴趣的:(openjdk学习)