上一篇主要查看了HostSpot的类解析过程,本质上是字节码文件读取解析的过程,解析的结果封装到对应的模型当中供虚拟机使用。HotSpot是基于堆栈的虚拟机,HotSpot执行引擎需要通过线程来划分管理方法栈。再深入HotSpot执行引擎如何运行之前,先来看看HotSpot线程。
一.线程
在Java种创建一个线程通常使用两种方式:extends Thread 或 implement Runnable,这两种方式是一回事(Thread实现了Runnable)。线程start()以后会关联到Host OS的线程上。
public class Thread implements Runnable {
@Override
public void run() { target.run();}
public synchronized void start() { start0(); }
private native void start0(); //调用jvm的JVM_StartThread
}
1.创建线程
hotspot/src/share/vm/prims/jvm.cpp
通过jcm.cpp启动线程
JVM_ENTRY(void, JVM_StartThread(JNIEnv* env, jobject jthread)){
......
native_thread = new JavaThread(&thread_entry, sz); //创建线程
......
native_thread->prepare(jthread); //准备线程
......
Thread::start(native_thread); //start线程
}
hotspot/src/share/vm/prims/jvm.cpp
创建线程时设置的run()方法回调
static void thread_entry(JavaThread* thread, TRAPS) {
HandleMark hm(THREAD);
Handle obj(THREAD, thread->threadObj());
JavaValue result(T_VOID);
//调用Thread.java的run方法
JavaCalls::call_virtual(&result,
obj,
KlassHandle(THREAD, SystemDictionary::Thread_klass()),
vmSymbols::run_method_name(), //run()方法
vmSymbols::void_method_signature(), //方法签名
THREAD);
}
hotspot/src/share/vm/runtime/thread.hpp
在HotSpot中按用途存在多种线程,操作符重载new调用allocate为新建线程分配内存
class Thread: public ThreadShadow {
void* operator new(size_t size) throw() { return allocate(size, true); }
}
hotspot/src/share/vm/runtime/thread.cpp
void* Thread::allocate(size_t size, bool throw_excpt, MEMFLAGS flags) {
void* real_malloc_addr =AllocateHeap(aligned_size, flags, CURRENT_PC,AllocFailStrategy::RETURN_NULL);
}
hotspot/src/share/vm/memory/allocation.inline.hpp
inline char* AllocateHeap(size_t size, MEMFLAGS flags,
char* p = (char*) os::malloc(size, flags, stack); //系统分配
return p;
}
hotspot/src/share/vm/runtime/thread.cpp
JavaThread::JavaThread(ThreadFunction entry_point, size_t stack_sz) :Thread()
{
initialize();
_jni_attach_state = _not_attaching_via_jni;
set_entry_point(entry_point); //设置run方法回调
// Create the native thread itself.
// %note runtime_23
os::ThreadType thr_type = os::java_thread;
thr_type = entry_point == &compiler_thread_entry ? os::compiler_thread :
os::java_thread;
os::create_thread(this, thr_type, stack_sz); //创建操作系统线程
}
hotspot/src/os/linux/vm/os_linux.cpp
创建一个对应的Linux线程,关联到OsThread,并使新创建的线程循环等待
bool os::create_thread(Thread* thread, ThreadType thr_type, size_t req_stack_size) {
// Allocate the OSThread object
OSThread* osthread = new OSThread(NULL, NULL);
// set the correct thread state
osthread->set_thread_type(thr_type);
//线程状态标记为已分配
osthread->set_state(ALLOCATED);
//关联
thread->set_osthread(osthread);
// init thread attributes
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
//计算线程栈大小
size_t stack_size = os::Posix::get_initial_stack_size(thr_type, req_stack_size);
stack_size = align_size_up(stack_size + os::Linux::default_guard_size(thr_type), vm_page_size());
pthread_attr_setstacksize(&attr, stack_size);
// Configure glibc guard page.
pthread_attr_setguardsize(&attr, os::Linux::default_guard_size(thr_type));
ThreadState state;
{
pthread_t tid; //线程ID
//创建一个线程,thread_native_entry为线程执行函数,thread为thread_native_entry的入参
int ret = pthread_create(&tid, &attr, (void* (*)(void*)) thread_native_entry, thread);
pthread_attr_destroy(&attr);
//关联到OSThread
osthread->set_pthread_id(tid);
// 线程等待
{
Monitor* sync_with_child = osthread->startThread_lock();
MutexLockerEx ml(sync_with_child, Mutex::_no_safepoint_check_flag);
while ((state = osthread->get_state()) == ALLOCATED) {
sync_with_child->wait(Mutex::_no_safepoint_check_flag);
}
}
}
//线程僵死,终止
if (state == ZOMBIE) {
thread->set_osthread(NULL);
delete osthread;
return false;
}
return true;
}
2.启动线程
hotspot/src/share/vm/runtime/thread.cpp
启动系统线程
void Thread::start(Thread* thread) {
if (!DisableStartThread) {
if (thread->is_Java_thread()) {
java_lang_Thread::set_thread_status(((JavaThread*)thread)->threadObj(),
java_lang_Thread::RUNNABLE);
}
os::start_thread(thread);
}
}
hotspot/src/share/vm/runtime/os.cpp
标记线程为RUNNABLE
void os::start_thread(Thread* thread) {
// guard suspend/resume
MutexLockerEx ml(thread->SR_lock(), Mutex::_no_safepoint_check_flag);
OSThread* osthread = thread->osthread();
//标记线程状态为可运行
osthread->set_state(RUNNABLE);
//唤醒
pd_start_thread(thread);
}
hotspot/src/os/linux/vm/os_linux.cpp
通知新创建的线程运行thread_native_entry函数
void os::pd_start_thread(Thread* thread) {
OSThread * osthread = thread->osthread();
Monitor* sync_with_child = osthread->startThread_lock();
MutexLockerEx ml(sync_with_child, Mutex::_no_safepoint_check_flag);
sync_with_child->notify();
}
hotspot/src/os/linux/vm/os_linux.cpp
入参为Thread,具体类型为JavaThread
static void *thread_native_entry(Thread *thread) {
static int counter = 0;
int pid = os::current_process_id();
alloca(((pid ^ counter++) & 7) * 128);
thread->initialize_thread_current();
OSThread* osthread = thread->osthread();
Monitor* sync = osthread->startThread_lock();
osthread->set_thread_id(os::current_thread_id());
if (UseNUMA) { //非平坦内存
int lgrp_id = os::numa_get_group_id();
if (lgrp_id != -1) {
thread->set_lgrp_id(lgrp_id);
}
}
// initialize signal mask for this thread
os::Linux::hotspot_sigmask(thread);
// 初始化浮点寄存器
os::Linux::init_thread_fpu_state();
// handshaking with parent thread
{
MutexLockerEx ml(sync, Mutex::_no_safepoint_check_flag);
//标记为初始化完成,通知父线程
osthread->set_state(INITIALIZED);
sync->notify_all();
// wait until os::start_thread()
while (osthread->get_state() == INITIALIZED) {
sync->wait(Mutex::_no_safepoint_check_flag);
}
}
//运行虚拟机现成的Run方法
thread->run();
return 0;
}
hotspot/src/share/vm/runtime/thread.cpp
线程被唤醒以后将执行此方法
void JavaThread::run() {
//线程本地分配缓存TLAB,这里将调用ThreadLocalAllocBuffer在年轻代堆内存为线程分配TLAB
//在虚拟机创建对象时会优先到TLAB去分配,一方面TLAB使用指针碰撞分配效率高,此外是线程独有有助于并发和垃圾回收
this->initialize_tlab();
// 记录栈基指针
this->record_base_of_stack_pointer();
//记录栈基和栈大小
this->record_stack_base_and_size();
//创建保护页
this->create_stack_guard_pages();
//缓存全局变量
this->cache_global_variables();
//线程状态_thread_new变为_thread_in_vm,进入safeponit
ThreadStateTransition::transition_and_fence(this, _thread_new, _thread_in_vm);
this->set_active_handles(JNIHandleBlock::allocate_block());
//将调用entry_ponit函数
thread_main_inner();
hotspot/src/share/vm/runtime/thread.cpp
继续调用Java层的run方法
void JavaThread::thread_main_inner() {
//无异常
if (!this->has_pending_exception() &&
!java_lang_Thread::is_stillborn(this->threadObj())) {
{
//线程名
this->set_native_thread_name(this->get_thread_name());
}
//调用entry_ponit即前文提到的jcm.cpp中的thread_entry函数
this->entry_point()(this, this);
}
this->exit(false);
delete this;
}
hotspot/src/share/vm/prims/jvm.cpp
这里再贴一下,这里将调用Thread.java的run()方法
static void thread_entry(JavaThread* thread, TRAPS) {
HandleMark hm(THREAD);
Handle obj(THREAD, thread->threadObj());
JavaValue result(T_VOID); //调用返回值
JavaCalls::call_virtual(&result, obj,
KlassHandle(THREAD, SystemDictionary::Thread_klass()),//Thread.java的KclassHandle
vmSymbols::run_method_name(), //对应run()方法方法名(可到符号表查看)
vmSymbols::void_method_signature(),//方法签名
THREAD);
}
二. 栈帧
什么Stub代码,Stub代码是HotSpot生成的固定调用点的代码。为什么需要Stub代码,HotSpot内部与Java代码调用的地方有两种形式JNI和Stub。JNI调用方式需要Java代码与JNI代码一一对应,每一个Java方法都对应一个JNI函数。而Stub是HosSpot内部为了统一调用Java函数而生成的固定调用点。通过手工汇编编写的一段存储于内存中的统一调用点。HotSpot内部按Java方法功能类别生成了多个调用点的Stub代码。当虚拟机执行到一个Java方法调用时,会统一转到合适的Stub调用点。该调用点会进行栈帧创建,参数传递处理,大大简化了设计。上述 JavaCalls::call_virtual()就是Stub调用的一个用例。
1.桩(Stub)代码调用
hotspot/src/share/vm/runtime/javaCalls.cpp
void JavaCalls::call_virtual(JavaValue* result, Handle receiver, KlassHandle spec_klass, Symbol* name, Symbol* signature, TRAPS) {
JavaCallArguments args(receiver); // One oop argument
call_virtual(result, spec_klass, name, signature, &args, CHECK);
}
hotspot/src/share/vm/runtime/javaCalls.cpp
void JavaCalls::call_virtual(JavaValue* result, KlassHandle spec_klass, Symbol* name, Symbol* signature, JavaCallArguments* args, TRAPS) {
CallInfo callinfo;
Handle receiver = args->receiver();
KlassHandle recvrKlass(THREAD, receiver.is_null() ? (Klass*)NULL : receiver->klass());
LinkInfo link_info(spec_klass, name, signature);
LinkResolver::resolve_virtual_call(callinfo, receiver, recvrKlass, link_info, true, CHECK);
methodHandle method = callinfo.selected_method();
assert(method.not_null(), "should have thrown exception");
// Invoke the method
JavaCalls::call(result, method, args, CHECK);
}
hotspot/src/share/vm/runtime/javaCalls.cpp
包裹异常,传递执行函数call_helper
void JavaCalls::call(JavaValue* result, const methodHandle& method, JavaCallArguments* args, TRAPS) {
os::os_exception_wrapper(call_helper, result, method, args, THREAD);
}
hotspot/src/share/vm/runtime/javaCalls.cpp
entry_point是java方法的调用点,在调用entry_ponit之前先调用call_stub,在调用call_stub之前会首先获取到方法对应的entry_point
void JavaCalls::call_helper(JavaValue* result, const methodHandle& method, JavaCallArguments* args, TRAPS) {
JavaThread* thread = (JavaThread*)THREAD; //线程
CompilationPolicy::compile_if_required(method, CHECK); //方法编译策略
address entry_point = method->from_interpreted_entry();//方法对应的entry_point
if (JvmtiExport::can_post_interpreter_events() && thread->is_interp_only_mode()) {
entry_point = method->interpreter_entry();
}
//返回类型
BasicType result_type = runtime_type_from(result);
bool oop_result_flag = (result->get_type() == T_OBJECT || result->get_type() == T_ARRAY);
//返回值
intptr_t* result_val_address = (intptr_t*)(result->get_value_addr());
//当前栈顶
address sp = os::current_stack_pointer();
//调用Java函数
{ JavaCallWrapper link(method, receiver, result, CHECK);
{ HandleMark hm(thread); // HandleMark used by HandleMarkCleaner
StubRoutines::call_stub()(
(address)&link, //方法链接
result_val_address, //返回值地址
result_type,//返回值类型
method(), //方法模型地址
entry_point, //方法调用Stub点
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());
}
}
}
}
hotspot/src/share/vm/runtime/stubRoutines.hpp
call_stub是一个宏转化调用,将一个固定调用点转换为CallStub函数
static address _call_stub_entry; //这是一个固定调用点
//固定函数
typedef void (*CallStub)(
address link,
intptr_t* result,
BasicType result_type,
Method* method,
address entry_point,
intptr_t* parameters,
int size_of_parameters,
TRAPS
);
//通过CAST_TO_FN_PTR将_call_stub_entry转换为指针函数CallStub,并传递8个参数给_call_stub_entry代表的调用点
static CallStub call_stub() { return CAST_TO_FN_PTR(CallStub, _call_stub_entry); }
hotspot/src/share/vm/utilities/globalDefinitions.hpp
#define CAST_TO_FN_PTR(func_type, value) (reinterpret_cast<func_type>(value))
那么问题来了_call_stub_entry这个固定调用点对应的机器码何时生成并赋值给_call_stub_entry的呢?
hotspot/src/share/vm/runtime/init.cpp
jint init_globals() {
......
stubRoutines_init1();
......
}
hotspot/src/share/vm/runtime/stubRoutines.cpp
void StubRoutines::initialize1() {
if (_code1 == NULL) {
_code1 = BufferBlob::create("StubRoutines (1)", code_size1); //缓存块
CodeBuffer buffer(_code1); //代码缓存块,存储固定调用点Stub代码
StubGenerator_generate(&buffer, false);
}
}
hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp
void StubGenerator_generate(CodeBuffer* code, bool all) {
StubGenerator g(code, all); //构造函数
}
hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp
StubGenerator(CodeBuffer* code, bool all) : StubCodeGenerator(code) {
if (all) {
generate_all();
} else {
generate_initial(); //走了这
}
}
void generate_initial() {
tubRoutines::_call_stub_entry = generate_call_stub(StubRoutines::_call_stub_return_address);
}
2.call_stub_entry的代码生成
hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp
_call_stub_entry是一个stub调用点,主要生成一段函数调用返回汇编指令,其过程类似中断,由于寄存器数量少需要共享使用因此需要将寄存器中的内容先保存,函数执行结束以后在归还,HotSpot完全使用栈来模拟函数调用过程,_call_stub_entry在虚拟机中只生成一次,并将生成的汇编代码保存在内存中。
- __ 前缀格式会调用汇编器生成汇编代码并存储在BufferBlob中,返回汇编代码地址
- 以栈基rbp为准计算入参在栈中的位置,如rsp_after_call_off=-12 偏移量为-12*8 = -96,以此类推
- 开始入栈,分配栈空间,在执行任何操作前先保存各寄存器的数据到上面第2步分配的栈地址处,获取寄存器控制权
- 传递入参进入栈,调用java方法(其实还是一个stub调用点entry_point)
- 保存entry_point返回结果
- 参数出栈
- 将之前保存在栈中的各寄存器的值恢复到寄存器中
- 重置栈顶指针,返回,归还控制权给调用方
address generate_call_stub(address& return_address) {
address start = __ pc(); //代码执行计数器
//以栈基rbp为准计算入参在栈中的位置
const Address rsp_after_call(rbp, rsp_after_call_off * wordSize); // 偏移量 -12 *8 = -96 的位置
const Address call_wrapper (rbp, call_wrapper_off * wordSize); // -6 * 8 = -48
const Address result (rbp, result_off * wordSize);
const Address result_type (rbp, result_type_off * wordSize);
const Address method (rbp, method_off * wordSize);
const Address entry_point (rbp, entry_point_off * wordSize);
const Address parameters (rbp, parameters_off * wordSize);
const Address parameter_size(rbp, parameter_size_off * wordSize);
const Address thread (rbp, thread_off * wordSize);
const Address r15_save(rbp, r15_off * wordSize);
const Address r14_save(rbp, r14_off * wordSize);
const Address r13_save(rbp, r13_off * wordSize);
const Address r12_save(rbp, r12_off * wordSize);
const Address rbx_save(rbp, rbx_off * wordSize);
//进入栈
__ enter();
//分配空间 12*8=96
__ subptr(rsp, -rsp_after_call_off * wordSize);
//保存寄存器的值,将寄存器腾出空来
#ifndef _WIN64
__ movptr(parameters, c_rarg5); // parameters
__ movptr(entry_point, c_rarg4); // entry_point
#endif
__ movptr(method, c_rarg3); // method
__ movl(result_type, c_rarg2); // result type
__ movptr(result, c_rarg1); // result
__ movptr(call_wrapper, c_rarg0); // call wrapper
// save regs belonging to calling function
__ movptr(rbx_save, rbx);
__ movptr(r12_save, r12);
__ movptr(r13_save, r13);
__ movptr(r14_save, r14);
__ movptr(r15_save, r15);
if (UseAVX > 2) {
__ movl(rbx, 0xffff);
__ kmovwl(k1, rbx);
}
#ifdef _WIN64
int last_reg = 15;
if (UseAVX > 2) {
last_reg = 31;
}
if (VM_Version::supports_evex()) {
for (int i = xmm_save_first; i <= last_reg; i++) {
__ vextractf32x4(xmm_save(i), as_XMMRegister(i), 0);
}
} else {
for (int i = xmm_save_first; i <= last_reg; i++) {
__ movdqu(xmm_save(i), as_XMMRegister(i));
}
}
const Address rdi_save(rbp, rdi_off * wordSize);
const Address rsi_save(rbp, rsi_off * wordSize);
__ movptr(rsi_save, rsi);
__ movptr(rdi_save, rdi);
#else
const Address mxcsr_save(rbp, mxcsr_off * wordSize);
{
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);
}
#endif
// Load up thread register
__ movptr(r15_thread, thread);
__ reinit_heapbase();
#ifdef ASSERT
// make sure we have no pending exceptions
{
Label L;
__ cmpptr(Address(r15_thread, Thread::pending_exception_offset()), (int32_t)NULL_WORD);
__ jcc(Assembler::equal, L);
__ stop("StubRoutines::call_stub: entered with pending exception");
__ bind(L);
}
#endif
//传递参数
BLOCK_COMMENT("pass parameters if any");
Label parameters_done;
__ movl(c_rarg3, parameter_size);
__ testl(c_rarg3, c_rarg3);
__ jcc(Assembler::zero, parameters_done);
Label loop;
__ movptr(c_rarg2, parameters); // parameter pointer
__ movl(c_rarg1, c_rarg3); // parameter counter is in c_rarg1
__ BIND(loop);
__ movptr(rax, Address(c_rarg2, 0));// get parameter
__ addptr(c_rarg2, wordSize); // advance to next parameter
__ decrementl(c_rarg1); // decrement counter
__ push(rax); // pass parameter
__ jcc(Assembler::notZero, loop);
//调用Java方法即调用entry_point
__ BIND(parameters_done);
__ movptr(rbx, method); // get Method*
__ movptr(c_rarg1, entry_point); // get entry_point
__ mov(r13, rsp); // set sender sp
BLOCK_COMMENT("call Java function");
__ call(c_rarg1);
BLOCK_COMMENT("call_stub_return_address:");
return_address = __ pc();
//返回结果保存处理
__ movptr(c_rarg0, result);
Label is_long, is_float, is_double, exit;
__ movl(c_rarg1, result_type);
__ cmpl(c_rarg1, T_OBJECT);
__ jcc(Assembler::equal, is_long);
__ cmpl(c_rarg1, T_LONG);
__ jcc(Assembler::equal, is_long);
__ cmpl(c_rarg1, T_FLOAT);
__ jcc(Assembler::equal, is_float);
__ cmpl(c_rarg1, T_DOUBLE);
__ jcc(Assembler::equal, is_double);
// handle T_INT case
__ movl(Address(c_rarg0, 0), rax);
__ BIND(exit);
//从栈弹出参数
__ lea(rsp, rsp_after_call);
......
//将之前保存在栈中的寄存器的数据重新恢复到各寄存器种
#ifdef _WIN64
// emit the restores for xmm regs
if (VM_Version::supports_evex()) {
for (int i = xmm_save_first; i <= last_reg; i++) {
__ vinsertf32x4(as_XMMRegister(i), as_XMMRegister(i), xmm_save(i), 0);
}
} else {
for (int i = xmm_save_first; i <= last_reg; i++) {
__ movdqu(as_XMMRegister(i), xmm_save(i));
}
}
#endif
__ movptr(r15, r15_save);
__ movptr(r14, r14_save);
__ movptr(r13, r13_save);
__ movptr(r12, r12_save);
__ movptr(rbx, rbx_save);
#ifdef _WIN64
__ movptr(rdi, rdi_save);
__ movptr(rsi, rsi_save);
#else
__ ldmxcsr(mxcsr_save);
#endif
//重置栈顶指针
__ addptr(rsp, -rsp_after_call_off * wordSize);
// 返回,归还控制权
__ pop(rbp);
__ ret(0);
......
return start;
}
3.entry_point的代码生成
上面的generate_call_stub只完成了函数调用的第一步,真正的Java函数还没调起,它对应一个entry_point也是一个stub调用点。这个调用点在哪里生成呢?
hotspot/src/share/vm/runtime/init.cpp
jint init_globals() { ...... interpreter_init(); ......}
hotspot/src/share/vm/interpreter/interpreter.cpp
void interpreter_init() { Interpreter::initialize() }
hotspot/src/share/vm/interpreter/templateInterpreter.cpp
void TemplateInterpreter::initialize() {
AbstractInterpreter::initialize(); //抽象计时器初始化
TemplateTable::initialize(); //模板初始化
// generate interpreter
{
int code_size = InterpreterCodeSize;
_code = new StubQueue(new InterpreterCodeletInterface, code_size, NULL,"Interpreter");
TemplateInterpreterGenerator g(_code); //模板解释器生成器
}
// initialize dispatch table
_active_table = _normal_table;
}
hotspot/src/share/vm/interpreter/templateInterpreterGenerator.cpp
TemplateInterpreterGenerator::TemplateInterpreterGenerator(StubQueue* _code): AbstractInterpreterGenerator(_code) {
_unimplemented_bytecode = NULL;
_illegal_bytecode_sequence = NULL;
generate_all();
}
hotspot/src/share/vm/interpreter/templateInterpreterGenerator.cpp
生成所有类别的entry_point
void TemplateInterpreterGenerator::generate_all() {
//宏定义,调用generate_method_entry生成汇编入口
#define method_entry(kind) \
{ CodeletMark cm(_masm, "method entry point (kind = " #kind ")"); \
Interpreter::_entry_table[Interpreter::kind] = generate_method_entry(Interpreter::kind); \
Interpreter::update_cds_entry_table(Interpreter::kind); \
}
//生成各种Java方法入口
method_entry(zerolocals)
method_entry(zerolocals_synchronized)
method_entry(empty)
method_entry(accessor)
method_entry(abstract)
method_entry(java_lang_math_sin )
method_entry(java_lang_math_cos )
method_entry(java_lang_math_tan )
method_entry(java_lang_math_abs )
method_entry(java_lang_math_sqrt )
method_entry(java_lang_math_log )
method_entry(java_lang_math_log10)
method_entry(java_lang_math_exp )
method_entry(java_lang_math_pow )
method_entry(java_lang_math_fmaF )
method_entry(java_lang_math_fmaD )
method_entry(java_lang_ref_reference_get)
......
}
hotspot/src/share/vm/interpreter/templateInterpreterGenerator.cpp
按类别生成entry_point
address TemplateInterpreterGenerator::generate_method_entry(AbstractInterpreter::MethodKind kind) {
......
if (native) {
entry_point = Interpreter::entry_for_kind(synchronized ? Interpreter::native_synchronized : Interpreter::native);
if (entry_point == NULL) {
entry_point = generate_native_entry(synchronized);
}
} else {
entry_point = Interpreter::entry_for_kind(synchronized ? Interpreter::zerolocals_synchronized : Interpreter::zerolocals);
if (entry_point == NULL) {
entry_point = generate_normal_entry(synchronized); //普通方法走这里
}
}
return entry_point;
}
hotspot/src/cpu/x86/vm/templateInterpreterGenerator_x86.cpp
- 计算局部变量数量
- 暂时弹出返回地址
- 计算局部变量第一个入参在堆栈中的位置保存在rlocals
- 生成固定帧
- 派发指令
address TemplateInterpreterGenerator::generate_normal_entry(bool synchronized) {
// ebx: Method*
// rbcp: sender sp
address entry_point = __ pc(); //计数器
const Address constMethod(rbx, Method::const_offset()); //方法地址
const Address access_flags(rbx, Method::access_flags_offset());//访问权限
const Address size_of_parameters(rdx, ConstMethod::size_of_parameters_offset()); //Java入参数量
const Address size_of_locals(rdx, ConstMethod::size_of_locals_offset()); //局部变量表最大槽数
//Java入参数量
__ movptr(rdx, constMethod);
__ load_unsigned_short(rcx, size_of_parameters);
//局部变量表最大槽数
__ load_unsigned_short(rdx, size_of_locals);
//局部变量数 = 局部变量表最大槽数 - Java入参数量
__ subl(rdx, rcx); //
//为了将方法入参和方法局部变量连在一起,先弹出返回地址
__ pop(rax);
//计算第一个入参在堆栈中的位置
__ lea(rlocals, Address(rsp, rcx, Interpreter::stackElementScale(), -wordSize));
//初始化局部变量区,分配栈空间
{
Label exit, loop;
__ testl(rdx, rdx);
__ jcc(Assembler::lessEqual, exit); // do nothing if rdx <= 0
__ bind(loop);
__ push((int) NULL_WORD); // initialize local variables
__ decrementl(rdx); // until everything initialized
__ jcc(Assembler::greater, loop);
__ bind(exit);
}
//生成固定帧
generate_fixed_frame(false);
......
//方法调用次数统计
Label invocation_counter_overflow;
Label profile_method;
Label profile_method_continue;
if (inc_counter) {
generate_counter_incr(&invocation_counter_overflow,
&profile_method,
&profile_method_continue);
if (ProfileInterpreter) {
__ bind(profile_method_continue);
}
}
//派发指令,开始执行Java方法的code指令
__ dispatch_next(vtos);
return entry_point;
}
hotspot/src/cpu/x86/vm/templateInterpreterGenerator_x86.cpp
- 返回地址重新入栈,开辟新栈帧
- rbcp值入栈,空出rbcp寄存器
- rbcp指向codebase
- Method*入栈
- Method*镜像压栈
- ConstantPoolCache压栈
- 局部变量表压栈
- 第一条字节码指令压栈
- 操作数栈底压栈
void TemplateInterpreterGenerator::generate_fixed_frame(bool native_call) {
// initialize fixed part of activation frame
__ push(rax); //局部变量入栈以后将返回地址重新入栈
__ enter(); //新栈帧,调整sp和bp
__ push(rbcp); //保存rbcp,空出rbcp寄存器
__ push((int)NULL_WORD); // leave last_sp as null
__ movptr(rbcp, Address(rbx, Method::const_offset())); //获取ConstMethod
__ lea(rbcp, Address(rbcp, ConstMethod::codes_offset())); //rbcp指向codebase
__ push(rbx); //Method*入栈
// Method*镜像压栈
__ load_mirror(rdx, rbx);
__ push(rdx);
//ConstantPoolCache压栈
__ movptr(rdx, Address(rbx, Method::const_offset()));
__ movptr(rdx, Address(rdx, ConstMethod::constants_offset()));
__ movptr(rdx, Address(rdx, ConstantPool::cache_offset_in_bytes()));
__ push(rdx); // set constant pool cache
//局部变量表压栈,rlocals是第一个入参在堆栈中的位置
__ push(rlocals); // set locals pointer
//第一条字节码指令压栈
if (native_call) {
__ push(0); // no bcp
} else {
__ push(rbcp); // set bcp
}
//操作数栈底压栈
__ push(0); // reserve word for pointer to expression stack bottom
__ movptr(Address(rsp, 0), rsp); //设置表达式栈底,表达式栈即固定帧栈顶
}
本文主要分析了HotSpot中线程和Stub调用的实现方式,为后面的内容做铺垫。Java的线程主要依靠宿主系统来实现,得益于HotSpot的设计,Java的线程很强大易用。