代码位于\hotspot\src\share\vm\runtime\Thread.cpp Line 2891~Line 3226
这个方法是JVM初始化的主要方法,300多行代码,代码虽然很多,但是思路很清晰,比较容易阅读。
这个方法是JVM初始化的主要方法,300多行代码,代码虽然很多,但是思路很清晰,比较容易阅读。
JVM初始化无外乎:解析参数、分配内存、创建内部数据结构、创建主线程、加载系统class等步骤。
这些代码均是相当好地被放在各个函数中,代码写的相对直白。
这些代码均是相当好地被放在各个函数中,代码写的相对直白。
下面讲讲初次看这个方法,比较难理解的一个地方
Thread.cpp Line 3138
SystemDictionary::compute_java_system_loader(THREAD);
这里面突然出现一个THREAD,很是突兀。
Thread.cpp Line 3138
SystemDictionary::compute_java_system_loader(THREAD);
这里面突然出现一个THREAD,很是突兀。
JVM是C++写成的,自然也继承了C的光荣传统:宏。
THREAD是宏,和它相关的宏还有:EXCEPTION_MARK、TRAPS、CHECK_0等。
它们均定义在:\hotspot\src\share\vm\utilities\exceptions.hpp
正如文件名exceptions.hpp所暗示的,这些宏和Exception处理有关系。这里的异常是指JVM代码中的异常,不是指Java程序的异常。
它们均定义在:\hotspot\src\share\vm\utilities\exceptions.hpp
正如文件名exceptions.hpp所暗示的,这些宏和Exception处理有关系。这里的异常是指JVM代码中的异常,不是指Java程序的异常。
exceptions.hpp Line 270
#define EXCEPTION_MARK Thread* THREAD; ExceptionMark __em(THREAD);
#define EXCEPTION_MARK Thread* THREAD; ExceptionMark __em(THREAD);
exceptions.hpp Line 155
#define THREAD __the_thread__
#define THREAD __the_thread__
所以THREAD实际上是 Thread* __the_thread__,这个变量在用VS调试的时候能清楚地通过IDE看到。
为了能使用THREAD必须首先使用宏:EXCEPTION_MARK
回到Thread::create_vm,在Line 3024处首先使用了EXCEPTION_MARK宏。
为了能使用THREAD必须首先使用宏:EXCEPTION_MARK
回到Thread::create_vm,在Line 3024处首先使用了EXCEPTION_MARK宏。
JVM代码中处理异常并没有使用C++的异常机制,而是用C的方式模拟了异常处理。
先看CHECK_0的定义
Exceptions.hpp Line179
#define CHECK_(result) THREAD); if (HAS_PENDING_EXCEPTION) return result; (0
#define CHECK_0 CHECK_(0)
先看CHECK_0的定义
Exceptions.hpp Line179
#define CHECK_(result) THREAD); if (HAS_PENDING_EXCEPTION) return result; (0
#define CHECK_0 CHECK_(0)
其中的HAS_PENDING_EXCEPTION的定义是
#define HAS_PENDING_EXCEPTION (((ThreadShadow*)THREAD)->has_pending_exception())
是查询当前Thread是否有没有处理的异常,有的话就返回true。
#define HAS_PENDING_EXCEPTION (((ThreadShadow*)THREAD)->has_pending_exception())
是查询当前Thread是否有没有处理的异常,有的话就返回true。
CHECK_0的含义就是如果有没有处理的异常,就返回0。
再看一个CHECK_0的使用
Thread::create_vm, Line 3050
initialize_class(vmSymbolHandles::java_lang_String(), CHECK_0);
Thread::create_vm, Line 3050
initialize_class(vmSymbolHandles::java_lang_String(), CHECK_0);
initialize_class的原型是
static void initialize_class(symbolHandle class_name, TRAPS) {
// ....
}
它的第二个参数是TRAPS,定义为
Exceptions.hpp Line 156
#define TRAPS Thread* THREAD
static void initialize_class(symbolHandle class_name, TRAPS) {
// ....
}
它的第二个参数是TRAPS,定义为
Exceptions.hpp Line 156
#define TRAPS Thread* THREAD
那么代码initialize_class(vmSymbolHandles::java_lang_String(), CHECK_0);经过宏展开之后是:
initialize_class(vmSymbolHandles::java_lang_String(), __the_thread__);
if (((ThreadShadow*)__the_thread__)->has_pending_expection())
return 0;
(0);
initialize_class(vmSymbolHandles::java_lang_String(), __the_thread__);
if (((ThreadShadow*)__the_thread__)->has_pending_expection())
return 0;
(0);
注意:上面的 (0); 不是我误写,是实实在在的宏产生的代码。
也就说initialize_class(vmSymbolHandles::java_lang_String(), CHECK_0);经过宏替换变成了三句代码。
第一句自然是对initialize_class的正常调用,其最后一个参数为__the_thread__
第二句是检查异常是否都已经被处理完毕。
第三句就是一个占位符性质的语句,什么也没有作,只是为了让产生的语句能顺利被编译,抵消多余的一个右括号。
也就说initialize_class(vmSymbolHandles::java_lang_String(), CHECK_0);经过宏替换变成了三句代码。
第一句自然是对initialize_class的正常调用,其最后一个参数为__the_thread__
第二句是检查异常是否都已经被处理完毕。
第三句就是一个占位符性质的语句,什么也没有作,只是为了让产生的语句能顺利被编译,抵消多余的一个右括号。
是不是仍然有点迷糊?OK,我们再来一遍。
因为:#define CHECK_(result) THREAD); if (HAS_PENDING_EXCEPTION) return result; (0
所以:CHECK_(0) <==> THREAD); if (HAS_PENDING_EXCEPTION) return 0; (0
因为:#define CHECK_(result) THREAD); if (HAS_PENDING_EXCEPTION) return result; (0
所以:CHECK_(0) <==> THREAD); if (HAS_PENDING_EXCEPTION) return 0; (0
因为:#define CHECK_0 CHECK_(0)
所以:CHECK_0 <==> THREAD); if (HAS_PENDING_EXCEPTION) return 0; (0
所以:CHECK_0 <==> THREAD); if (HAS_PENDING_EXCEPTION) return 0; (0
那么 initialize_class(... , CHECK_0);
<==> initialize_class(... , THREAD); if (HAS_PENDING_EXCEPTION) return 0; (0);
<==> initialize_class(... , THREAD); if (HAS_PENDING_EXCEPTION) return 0; (0);
总结一下
1、一个函数的最后一个参数是TRAPS, 则说明该函数需要应用到如上的异常处理场景。
2、为了让一个行数应用到如上场景,它只能是最后一个参数是TRAPS。否则经过宏替换后,不能正常编译。
3、在调用该函数之前,需要先用宏EXCEPTION_MARK来声明变量。