hotspot源码的确比较恶心,要懂C/C++,还要懂ASM,算法也要掌握.直接劝退.看了一整天,本来迷迷糊糊,现在更加迷迷糊糊了.= =
javaCalls.cpp
StubRoutines::call_stub()(
//连接器
(address)&link,
// (intptr_t*)&(result->_value), // see NOTE above (compiler problem)
//函数返回值地址
result_val_address, // see NOTE above (compiler problem)
//返回类型
result_type,
//jvm内部所表示的java方法对象,可获取java函数编译后的字节码信息,如继承,返回,注解,入参,函数名称,返回值等信息
method(),
//jvm调用java方法的例程入口,也就是预生成的机器指令.从这里拿到java函数所对应的第一个字节码指令,然后调用java函数
entry_point,
//入参集合
args->parameters(),
//入参数量
args->size_of_parameters(),
//当前线程对象
CHECK
);
stubRoutines.hpp
static CallStub call_stub(){
return CAST_TO_FN_PTR(CallStub, _call_stub_entry);
//等同于 ((CallStub)(castable_address(_call_stub_entry))) =》 address_word(_call_stub_entry) ;
//在linux上 (CallStub)unsigned int(_call_stub_entry)
//unsigned int(unsigned char * )
}
CAST_TO_FN_PTR在globalDefinitions.hpp定义,
#define CAST_TO_FN_PTR(func_type, value) ((func_type)(castable_address(value)))
castable_address声明为一个内联函数
inline address_word castable_address(address x) { return address_word(x) ; }
address_word的类型
/*
* 分别三个平台定义了
* linux globalDefinitions_gcc.hpp
*/
typedef uintptr_t address_word;
我们查看linux平台
stubGenerator_x86_32.cpp
typedef unsigned int uintptr_t;
可以看得到
CAST_TO_FN_PTR(CallStub, _call_stub_entry)<=>(CallStub)unsigned int(_call_stub_entry)
那么_call_stub_entry的值是啥了?
stubRoutines.hpp
static address _call_stub_entry;
globalDefinitions.hpp
typedef unsigned char u_char;
typedef u_char* address;
可以看得出最终的形式为:
(CallStub)uunsigned int(unsigned char * )
_call_stub_entry的赋值过程:
stubGenerator_x86_32.cpp
//给_call_stub_entry赋值
StubRoutines::_call_stub_entry =
generate_call_stub(StubRoutines::_call_stub_return_address);
自此初始化完成,紧接着就是调用了.
javaCalls.cpp
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,
//jvm内部所表示的java方法对象,可获取java函数编译后的字节码信息,如继承,返回,注解,入参,函数名称,返回值等信息
method(),
//jvm调用java方法的例程入口,也就是预生成的机器指令.从这里拿到java函数所对应的第一个字节码指令,然后调用java函数
entry_point,
//入参集合
args->parameters(),
//入参数量
args->size_of_parameters(),
//当前线程对象
CHECK
);
link
JavaCallWrapper link(method, receiver, result, CHECK);
连接器,主要将java函数调用者和被调用者搭建桥梁
javaCalls.hpp
//连接器,主要将java函数调用者和被调用者搭建桥梁
class JavaCallWrapper: StackObj {
friend class VMStructs;
private:
//当前java函数所在线程
JavaThread* _thread; // the thread to which this call belongs
//本地调用句柄
JNIHandleBlock* _handles; // the saved handle block
//调用者方法对象
Method* _callee_method; // to be able to collect arguments if entry frame is top frame
//被调用者,非静态java方法
oop _receiver; // the receiver of the call (if a non-static call)
//java线程堆栈对象
JavaFrameAnchor _anchor; // last thread anchor state that we must restore
//java方法所返回的值
JavaValue* _result; // result value
JVM初始化链路
在红框处对**_call_stub_entry**进行了初始化
stubGenerator_x86_32.cpp
//给_call_stub_entry赋值
StubRoutines::_call_stub_entry =
generate_call_stub(StubRoutines::_call_stub_return_address);
generate_call_stub
address generate_call_stub(address& return_address) {
StubCodeMark mark(this, "StubRoutines", "call_stub");
//得到当前入口的内存地址
address start = __ pc();
// stub code parameters / addresses
assert(frame::entry_frame_call_wrapper_offset == 2, "adjust this code");
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);
//相当于 &result = 3N(%ebp),从内存中获取数据
//如下参数在被调用者内部.用于保存调用者的信息
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();
//计算即将被调用java函数入参所需堆栈空间
//movl 0x20(%ebp) %ecx 将parameter_size值传给ecx寄存器
__ movptr(rcx, parameter_size); // parameter counter
//shl $0x2 %ecx 将ecx寄存器值左移2位,也就是*4,因为32平台,每个指针占用32内存,也就是4字节.
__ shlptr(rcx, Interpreter::logStackElementSize); // convert parameter count to bytes
//add $0x10,%ecx 额外申请16字节空间,用于存储rdi,rsi,rbx,mxcsr4个寄存器值
__ addptr(rcx, locals_count_in_bytes); // reserve space for register saves
//sub %ecx,%esp 申请rcx大小堆栈空间
__ subptr(rsp, rcx);
//and $0xfffffff0,%esp 堆栈按16位对齐,若不对齐则减去后4位值
__ andptr(rsp, -(StackAlignmentInBytes)); // Align stack
// save rdi, rsi, & rbx, according to C calling conventions
//保存rdi,rsi,rbx 调用者现场
//mov %edi,-0x4(%ebp)
__ movptr(saved_rdi, rdi);
// mov %esi,-0x8(%ebp) esi用于java字节码寻址
__ movptr(saved_rsi, rsi);
// mov %ebx,-0xc(%ebp)
__ movptr(saved_rbx, rbx);
// save and initialize %mxcsr
if (sse_save) {
Label skip_ldmx;
__ stmxcsr(mxcsr_save);
__ movl(rax, mxcsr_save);
__ andl(rax, MXCSR_MASK); // Only check control and mask bits
ExternalAddress mxcsr_std(StubRoutines::addr_mxcsr_std());
__ cmp32(rax, mxcsr_std);
__ jcc(Assembler::equal, skip_ldmx);
__ ldmxcsr(mxcsr_std);
__ bind(skip_ldmx);
}
// make sure the control word is correct.
__ fldcw(ExternalAddress(StubRoutines::addr_fpu_cntrl_wrd_std()));
#ifdef ASSERT
// make sure we have no pending exceptions
{ Label L;
__ movptr(rcx, thread);
__ cmpptr(Address(rcx, Thread::pending_exception_offset()), (int32_t)NULL_WORD);
__ jcc(Assembler::equal, L);
__ stop("StubRoutines::call_stub: entered with pending exception");
__ bind(L);
}
#endif
// pass parameters if any
BLOCK_COMMENT("pass parameters if any");
Label parameters_done;
//参数数量
//mov 0x20(%ebp),%ecx 将parameter_size存ecx
__ movl(rcx, parameter_size); // parameter counter
//测试parameter_size是否=0,若是则直接跳过参数处理
//test %ecx,ecx
__ testl(rcx, rcx);
__ jcc(Assembler::zero, parameters_done);
// parameter passing loop
Label loop;
// Copy Java parameters in reverse order (receiver last)
// Note that the argument order is inverted in the process
// source is rdx[rcx: N-1..0]
// dest is rsp[rbx: 0..N-1]
//第一个入参地址
//mov 0x1c(%ebp),%edx 用edx记录第一个入参指针
__ movptr(rdx, parameters); // parameter pointer
//%ebx设0
//xor %ebx,%ebx
__ xorptr(rbx, rbx);
//循环将java函数参数压栈
__ BIND(loop);
// get parameter
// 获取第N个入参位置:edx+(N-1)*4
//mov -0x4(%edx,%ecx,4),%eax
__ movptr(rax, Address(rdx, rcx, Interpreter::stackElementScale(), -wordSize));
//mov %eax,(%esp,%ebx,4)
__ movptr(Address(rsp, rbx, Interpreter::stackElementScale(),
Interpreter::expr_offset_in_bytes(0)), rax); // store parameter
//inc %ebx
__ increment(rbx);
//dec %ecx 参数数量-1,也就是循环次数-1,这里主要采用逆序遍历
__ decrement(rcx);
//jne 0x地址
__ jcc(Assembler::notZero, loop);
// call Java function
__ BIND(parameters_done);
//mov 0x14(%ebp),%ebx 将method首地址传给ebx
__ movptr(rbx, method); // get Method*
//mov 0x18(%ebp),%eax 将entry_point传给eax
__ movptr(rax, entry_point); // get entry_point
//mov %esp,%esi 将当前栈顶保存esi中
__ mov(rsi, rsp); // set sender sp
BLOCK_COMMENT("call Java function");
//call *%eax 调用entry_point
__ call(rax);
BLOCK_COMMENT("call_stub_return_address:");
return_address = __ pc();
oop-klass模型
oop体系
oopsHierarchy.hpp
定义的各种oop(用来描述对象实例信息)
typedef class oopDesc* oop;
typedef class instanceOopDesc* instanceOop;
typedef class arrayOopDesc* arrayOop;
typedef class objArrayOopDesc* objArrayOop;
typedef class typeArrayOopDesc* typeArrayOop;
定义的各种class信息
class Klass;
class InstanceKlass;
class InstanceMirrorKlass;
class InstanceClassLoaderKlass;
class InstanceRefKlass;
class ArrayKlass;
class ObjArrayKlass;
class TypeArrayKlass;
oop.hpp
//所有oopDesc的父类
class oopDesc {
friend class VMStructs;
private:
//标记,线程状态,并发锁,GC分代信息等内部标识
volatile markOop _mark;
//标识元数据信息,如变量,方法,父类,所实现接口等信息
union _metadata {
Klass* _klass;
narrowKlass _compressed_klass;
} _metadata;
classFileParser.cpp
ClassFileStream* cfs = stream();
...
//解析魔数
u4 magic = cfs->get_u4_fast();
ClassFileStream主要用于读取字节码流中数据,结构如下:
classFileStream.hpp
class ClassFileStream: public ResourceObj {
private:
u1* _buffer_start; // Buffer bottom
u1* _buffer_end; // Buffer top (one past last element)
//当前字节码流读到位置
u1* _current; // Current buffer position
char* _source; // Source of stream (directory name, ZIP/JAR archive name)
bool _need_verify; // True if verification is on for the class file
从字节码流中读取4字节内容
u4 get_u4_fast() {
u4 res = Bytes::get_Java_u4(_current);
_current += 4;
return res;
}
bytes_x86.hpp
/**
* 从内存指定位置读取4字节并转成JVM内部u4类型
*/
static inline u4 get_Java_u4(address p) { return swap_u4(get_native_u4(p)); }
/**
* 从内存指定位置读取4字节并转成u4类型
*/
static inline u4 get_native_u4(address p) { return *(u4*)p; }
大小端转换
bytes_linux_x86.inline.hpp
/**
* u4类型大端小端转换
*/
inline u4 Bytes::swap_u4(u4 x) {
#ifdef AMD64
return bswap_32(x);
#else
u4 ret;
__asm__ __volatile__ (
"bswap %0"
:"=r" (ret) // output : register 0 => ret
:"0" (x) // input : x => register 0
:"0" // clobbered register
);
return ret;
#endif // AMD64
}