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的,直接调用解析器的入口,由解释器再进行操作。