Repository navigation
share C2_CompilerThread
ceragon edited this page Dec 8, 2021
·
3 revisions
- 声明位于 compileBroker.cpp 中
void CompileBroker::init_compiler_sweeper_threads() {
JavaThread *ct = make_thread(thread_handle, _c2_compile_queue, _compilers[1], CHECK);
}- 创建位于make_thread 中, 我们只关心创建和启动过程,所以省略无关代码
JavaThread* CompileBroker::make_thread(jobject thread_handle, CompileQueue* queue, AbstractCompiler* comp, TRAPS) {
JavaThread* thread = NULL;
CompilerCounters* counters = new CompilerCounters();
thread = new CompilerThread(queue, counters);
Threads::add(thread);
Thread::start(thread);
}- 线程的 run 方法如下, 同样省略不关心的代码
void JavaThread::run() {
thread_main_inner();
}- 主要是执行 thread_main_inner() 这个方法
void JavaThread::thread_main_inner() {
// Execute thread entry point unless this thread has a pending exception
// or has been stopped before starting.
// Note: Due to JVM_StopThread we can have pending exceptions already!
if (!this->has_pending_exception() &&
!java_lang_Thread::is_stillborn(this->threadObj())) {
this->entry_point()(this, this);
}
}- 其中官方注释写的很清楚,如果没有异常或者在启动中被stop,那么就可以正常执行线程的 entry point。对于C2 编译线程来说,它的callPoint是下面位置
CompilerThread::CompilerThread(CompileQueue* queue,
CompilerCounters* counters)
: JavaThread(&compiler_thread_entry) {
}- 也就是构造线程对象的时候,entry point 就赋值给父类了,compiler_thread_entry 内容如下:
static void compiler_thread_entry(JavaThread* thread, TRAPS) {
CompileBroker::compiler_thread_loop();
}- 本thread的主要逻辑如下所示
void CompileBroker::compiler_thread_loop() {
CompilerThread* thread = CompilerThread::current();
CompileQueue* queue = thread->queue();
while (!is_compilation_disabled_forever()) {
CompileTask* task = queue->get();
// UseCompiler 默认是 true, AlwaysCompileLoopMethods 默认是 false
// 除非禁用 运行时编译,否则 should_compile_new_jobs 为 true
if ((UseCompiler || AlwaysCompileLoopMethods) && CompileBroker::should_compile_new_jobs()) {
invoke_compiler_on_method(task);
}
// 默认是 true
if (UseDynamicNumberOfCompilerThreads) {
possibly_add_compiler_threads();
}
}
}- 上面代码的主要逻辑是执行 invoke_compiler_on_method,这个方法说实话特别复杂,但我主要关心输出是什么,以及存放到了什么位置。所以以下代码省略无关内容
void CompileBroker::invoke_compiler_on_method(CompileTask* task) {
AbstractCompiler* comp = task->compiler();
comp->compile_method(&ci_env, target, osr_bci, directive);
}- 继续追踪 compile_method
void C2Compiler::compile_method(ciEnv* env, ciMethod* target, int entry_bci, DirectiveSet* directive) {
while (!env->failing()) {
Compile C(env, this, target, entry_bci, subsume_loads, do_escape_analysis, eliminate_boxing, directive);
}
}- 编译的主体逻辑在 Compile 的构造函数中, 我完全看不懂里面的内容,但我知道这个方法一定会产生一个输出结果,所以省略无关代码,只看输出内容
Compile::Compile( ciEnv* ci_env, C2Compiler* compiler, ciMethod* target, int osr_bci,
bool subsume_loads, bool do_escape_analysis, bool eliminate_boxing, DirectiveSet* directive){
// 我认识这两个单词,代码生成
Code_Gen();
}- 貌似这个Code_Gen 方法才是主体,里面的逻辑我还是看不懂,所以你懂的
void Compile::Code_Gen() {
// 我也认识这个单词,输出或者导出
Output();
}- 看下 Output 方法
void Compile::Output() {
uint* blk_starts = NEW_RESOURCE_ARRAY(uint, _cfg->number_of_blocks() + 1);
blk_starts[0] = 0;
// Initialize code buffer and process short branches.
CodeBuffer* cb = init_buffer(blk_starts);
fill_buffer(cb, blk_starts);
}- 我不关心往cb里中填充了什么内容,我只关心这些内容存在了内存的什么位置,可以看到主要是 NEW_RESOURCE_ARRAY 这个方法
- C2 线程申请内存的代码
#define NEW_RESOURCE_ARRAY(type, size)\
(type*) resource_allocate_bytes((size) * sizeof(type))- 实际方法
extern char* resource_allocate_bytes(size_t size, AllocFailType alloc_failmode) {
return Thread::current()->resource_area()->allocate_bytes(size, alloc_failmode);
}- allocate_bytes 应该就是分配空间的方法,关键要看 resource_area() 这个方法导致是什么区域
Thread::Thread() {
set_resource_area(new (mtThread)ResourceArea());
}- ResourceArea 的构造方法如下:
ResourceArea(MEMFLAGS flags = mtThread) : Arena(flags) {
}
Arena::Arena(MEMFLAGS flag) : _flags(flag), _size_in_bytes(0) {
_first = _chunk = new (AllocFailStrategy::EXIT_OOM, Chunk::init_size) Chunk(Chunk::init_size);
_hwm = _chunk->bottom(); // Save the cached hwm, max
_max = _chunk->top();
MemTracker::record_new_arena(flag);
set_size_in_bytes(Chunk::init_size);
}- 接着再来看 allocate_bytes 这个方法
inline char* ResourceArea::allocate_bytes(size_t size, AllocFailType alloc_failmode) {
return (char*)Amalloc(size, alloc_failmode);
}
void* Amalloc(size_t x, AllocFailType alloc_failmode = AllocFailStrategy::EXIT_OOM) {
if (!check_for_overflow(x, "Arena::Amalloc", alloc_failmode))
return NULL;
}