虽然说解释执行模式是逐字逐句翻译给目标平台运行的,但这样的过程未免太过缓慢,如 果能把字节码说的话做成纸条,运行时只要把对应的纸条交给目标平台就可以了,这样,执行速度就会明显提升。JVM的Hotspot虚拟机的模板解释器就是 用这种方法来解释执行的。在开始分析之前,先了解一下JVM的执行方式。
(1).边解释边运行,即每次解释一条字节码并运行其解释的本地代码,这种执行引擎速度相对很慢
(2).JIT(即时编译)具有更快的运行速度但是需要更多的内存,方法被第一次调用时,字节码编译生成的本地代码将会被缓存,这样在该方法下次被调用的时候,将取出缓冲的本地代码直接运行
(3).自适应优化,对于经常被调用的方法,则会缓存其编译产生成的本地代码,对于其他较少被调用的代码,仍对其采用解释执行的方法。
(4).片上虚拟机,即虚拟机的执行引擎直接嵌入在片上
HotSpot虚拟机可以配置为以下运行模式:
-Xint:解释模式
-Xcomp:编译模式
-Xmixed:混合模式
(通过java -version就可以查看虚拟机的运行模式)
HotSpot在启动时,会为所有字节码创建在目标平台上运行的解释运行的机器码,并存放在CodeCache中,在解释执行字节码的过程中,就会从CodeCache中取出这些本地机器码并执行。
Hotspot虚拟机的细节技术实现值得借鉴,如果你觉得源码甚至汇编代码比较枯燥的话,也可以大致了解相关模块的组件、工作流程,对相关实现有一定的认识。
下面就从模板解释器的初始化开始,分析HotSpot的解释代码的生成。
在创建虚拟机时,在初始化全局模块过程中,会调用interpreter_init()初始化模板解释器,模板解释器的初始化包括抽象解释器AbstractInterpreter的初始化、模板表TemplateTable的初始化、CodeCache的Stub队列StubQueue的初始化、解释器生成器InterpreterGenerator的初始化。
void
TemplateInterpreter::initialize() {
if
(_code != NULL)
return
;
// assertions
//...
AbstractInterpreter::initialize();
TemplateTable::initialize();
// generate interpreter
{ ResourceMark rm;
TraceTime timer(
"Interpreter generation"
, TraceStartupTime);
int
code_size = InterpreterCodeSize;
NOT_PRODUCT(code_size *=
4
;)
// debug uses extra interpreter code space
_code =
new
StubQueue(
new
InterpreterCodeletInterface, code_size, NULL,
"Interpreter"
);
InterpreterGenerator g(_code);
if
(PrintInterpreter) print();
}
// initialize dispatch table
_active_table = _normal_table;
}
-
AbstractInterpreter是基于汇编模型的解释器的共同基类,定义了解释器和解释器生成器的抽象接口。
-
模板表TemplateTable保存了各个字节码的模板(目标代码生成函数和参数)。TemplateTable的初始化调用def()将所有字节码的目标代码生成函数和参数保存在_template_table或_template_table_wide(wide指令)模板数组中
// interpr. templates
// Java spec bytecodes ubcp|disp|clvm|iswd in out generator argument
def(Bytecodes::_nop , ____|____|____|____, vtos, vtos, nop , _ );
def(Bytecodes::_aconst_null , ____|____|____|____, vtos, atos, aconst_null , _ );
def(Bytecodes::_iconst_m1 , ____|____|____|____, vtos, itos, iconst , -1 );
def(Bytecodes::_iconst_0 , ____|____|____|____, vtos, itos, iconst , 0 );
def(Bytecodes::_iconst_1 , ____|____|____|____, vtos, itos, iconst , 1 );
def(Bytecodes::_iconst_2 , ____|____|____|____, vtos, itos, iconst , 2 );
//...其他字节码的模板定义
其中,def()是查看数组对应项是否为空,若为空则初始化该数组项。
Template* t = is_wide ? template_for_wide(code) : template_for(code);// setup entryt->initialize(flags, in, out, gen, arg);
_template_table或_template_table_wide的数组项就是Template对象,即字节码的模板,Template的结构如下:
class Template VALUE_OBJ_CLASS_SPEC {private:enum Flags {uses_bcp_bit, // set if template needs the bcp pointing to bytecodedoes_dispatch_bit, // set if template dispatches on its owncalls_vm_bit, // set if template calls the vmwide_bit // set if template belongs to a wide instruction};