HotSpot线程与栈帧

上一篇主要查看了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在虚拟机中只生成一次,并将生成的汇编代码保存在内存中。

  1. __ 前缀格式会调用汇编器生成汇编代码并存储在BufferBlob中,返回汇编代码地址
  2. 以栈基rbp为准计算入参在栈中的位置,如rsp_after_call_off=-12 偏移量为-12*8 = -96,以此类推
  3. 开始入栈,分配栈空间,在执行任何操作前先保存各寄存器的数据到上面第2步分配的栈地址处,获取寄存器控制权
  4. 传递入参进入栈,调用java方法(其实还是一个stub调用点entry_point)
  5. 保存entry_point返回结果
  6. 参数出栈
  7. 将之前保存在栈中的各寄存器的值恢复到寄存器中
  8. 重置栈顶指针,返回,归还控制权给调用方
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

  1. 计算局部变量数量
  2. 暂时弹出返回地址
  3. 计算局部变量第一个入参在堆栈中的位置保存在rlocals
  4. 生成固定帧
  5. 派发指令
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

  1. 返回地址重新入栈,开辟新栈帧
  2. rbcp值入栈,空出rbcp寄存器
  3. rbcp指向codebase
  4. Method*入栈
  5. Method*镜像压栈
  6. ConstantPoolCache压栈
  7. 局部变量表压栈
  8. 第一条字节码指令压栈
  9. 操作数栈底压栈
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的线程很强大易用。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值