解释器入口地址的生成书接上回我们已经知道entry_point指向的是函数的解释器入口地址。/* javaCalls.cpp */ address entry_point method-from_interpreted_entry();//这里提供了函数的解释器入口 ... 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, parameter_address, args-size_of_parameters(), CHECK );1 函数入口表那么hotspot是如何为函数生成解释器入口的呢实际上hotspot采用了一种表的方式来保存各种类型函数入口的方式。其定义如下。/*abstractInterpreter.cpp*/ address AbstractInterpreter::_entry_table [AbstractInterpreter::number_of_method_entries];其中AbstractInterpreter::number_of_method_entries来自以下枚举定义/*abstractInterpreter.hpp*/ enum MethodKind { zerolocals, // method needs locals ... java_lang_math_sin, // implementation of java.lang.Math.sin (x) ... number_of_method_entries, invalid -1 };该枚举用于描述不同的函数类型number_of_method_entries用了C中的一个枚举技巧即最后一个值表示整个枚举的个数正好可以用来设置数组的长度。当一个函数需要生成解释器入口时只需要将函数作为参数传入以下函数即可获得/*abstractInterpreter.hpp*/ static address entry_for_kind(MethodKind k) { return _entry_table[k]; } static address entry_for_method(const methodHandle m) { return entry_for_kind(method_kind(m)); }2 函数链接很明显当调用entry_for_kind时即可获得函数的解释器入口地址。因此只要在函数连接过程时调用该方法即可设置函数的解释器入口。代码如下void Method::link_method(const methodHandle h_method, TRAPS) { ... address entry Interpreter::entry_for_method(h_method); ... set_interpreter_entry(entry); ... }关于函数链接的内容此处不表。这里进入set_interpreter_entry中可以看到解释器地址会给函数以下成员变量。void set_interpreter_entry(address entry) { if (_i2i_entry ! entry) { _i2i_entry entry;//这里是interpreter to interpreter } if (_from_interpreted_entry ! entry) { _from_interpreted_entry entry; //这里是解释器入口地址 } }可以通过gdb来检查何时执行了上述函数(gdb)b Method::set_interpreter_entryifentry!0x0程序在下面停下了Thread2javahit Breakpoint2, Method::set_interpreter_entry(this0x7fffe8800a70,entry0x7fffed00e5e0H\213K\020\017\267I,XL\215t\314\370h)at /home/jx/src/openjdk/src/hotspot/share/oops/method.hpp:496496if(_i2i_entry!entry){通过bt来查看究竟是什么造成了解释器入口的修改(gdb)bt#0 Method::set_interpreter_entry (this0x7fffe8800a70,entry0x7fffed00e5e0H\213K\020\017\267I,XL\215t\314\370h)at /home/jx/src/openjdk/src/hotspot/share/oops/method.hpp:496#1 0x00007ffff69aab9e in Method::link_method (this0x7fffe8800a70,h_method...,__the_thread__0x7ffff0028870)at /home/jx/src/openjdk/src/hotspot/share/oops/method.cpp:1204可以看到是方法连接时函数的入口地址发生了修改进入该函数查看void Method::link_method(const methodHandle h_method, TRAPS) { ... address entry Interpreter::entry_for_method(h_method); assert(entry ! NULL, interpreter entry must be non-null); // Sets both _i2i_entry and _from_interpreted_entry set_interpreter_entry(entry); ...see, 地址是从Interpreter::entry_for_method(h_method);此处取值3 解释器入口地址生成由于编译器是采用先定义后使用的方式因此上述地址在函数调用前必然会准备好通过查找代码可知以下函数实现了普通函数的解释器入口。/*templateInterpreterGenerator.cpp*/ address TemplateInterpreterGenerator::generate_method_entry( AbstractInterpreter::MethodKind kind) { ... entry_point Interpreter::entry_for_kind(synchronized ? Interpreter::zerolocals_synchronized : Interpreter::zerolocals);//非特殊函数 if (entry_point NULL) { entry_point generate_normal_entry(synchronized); }还是跟桩代码一样可以看到汇编片段由generate_normal_entry生成生成后将首地址返回。通过gdb定位可知x86架构实现如下address TemplateInterpreterGenerator::generate_normal_entry(bool synchronized) { ... address entry_point __ pc(); ... return entry_point; }这里entry_point就是生成的汇编段的首地址。