OpenJDK 17 源碼的實現邏輯,handle_polling_page_exception
?函數在方法返回時的調用流程如下:
調用流程分析:
棧水印檢查觸發跳轉:
當線程執行方法返回前的安全點輪詢時(
MacroAssembler::safepoint_poll
?中?at_return=true
)如果棧指針超出安全區域(
cmpptr
?比較結果為?above
),會跳轉到關聯的?slow_path
?標簽這個?
slow_path
?標簽由?C2SafepointPollStub
?管理
樁代碼生成:
C2SafepointPollStubTable::emit()
?遍歷所有安全點條目為每個條目調用?
emit_stub()
?生成樁代碼
cpp
void emit_stub(MacroAssembler& masm, C2SafepointPollStub* entry) const {select_emit_stub<VM_Version::supports_stack_watermark_barrier()>(masm, entry); }
樁代碼核心邏輯:
在?
emit_stub_impl()
?中生成實際匯編代碼:cpp
__ bind(entry->_stub_label); // 計算安全點返回地址 InternalAddress safepoint_pc(...);// 保存返回地址到線程控制塊 __ lea(rscratch1, safepoint_pc); __ movptr(Address(r15_thread, JavaThread::saved_exception_pc_offset()), rscratch1);// 跳轉到異常處理入口 __ jump(callback_addr); // callback_addr = polling_page_return_handler_blob
處理函數綁定:
polling_page_return_handler_blob
?在 JVM 初始化時創建:cpp
_polling_page_return_handler_blob = generate_handler_blob(CAST_FROM_FN_PTR(address, SafepointSynchronize::handle_polling_page_exception),POLL_AT_RETURN );
該 blob 將?
handle_polling_page_exception
?函數地址嵌入到生成的機器代碼中
關鍵調用路徑:
text
執行線程 → 方法返回前的輪詢檢查│├─ 棧水印檢查失敗 → 跳轉到 slow_path (C2SafepointPollStub)│ ││ └─ 樁代碼執行:│ 1. 保存返回地址到 JavaThread::saved_exception_pc_offset()│ 2. 跳轉到 polling_page_return_handler_blob│ ││ └─ 執行 handle_polling_page_exception()│ ││ └─ 安全點同步處理│└─ 正常繼續執行
技術要點:
上下文保存:
樁代碼通過?
saved_exception_pc_offset()
?保存原始返回地址確保異常處理后能正確返回到原執行點
平臺適配:
使用?
select_emit_stub
?模板實現條件編譯僅當?
VM_Version::supports_stack_watermark_barrier()
?為 true 時生成樁代碼
異常處理機制:
cpp
void SafepointSynchronize::handle_polling_page_exception(JavaThread* thread) {// 1. 檢查安全點狀態// 2. 阻塞線程直到安全點操作完成// 3. 恢復線程執行(通過 saved_exception_pc 返回) }
水印檢查優化:
在 nmethod 中使用?
rsp
?而非?rbp
,因為:cpp
// 當 in_nmethod 時,棧指針已在輪詢前遞增 cmpptr(in_nmethod ? rsp : rbp, ...);
總結:
當線程在方法返回前檢測到棧水印越界時,會通過預先生成的樁代碼跳轉到?handle_polling_page_exception
?函數。該函數負責將線程掛起直到安全點操作完成,然后通過保存的返回地址恢復執行。這種機制實現了高效的安全點協作,同時保證了棧收縮時的內存安全。
##源碼
#define __ masm.
void C2SafepointPollStubTable::emit_stub_impl(MacroAssembler& masm, C2SafepointPollStub* entry) const {assert(SharedRuntime::polling_page_return_handler_blob() != NULL,"polling page return stub not created yet");address stub = SharedRuntime::polling_page_return_handler_blob()->entry_point();RuntimeAddress callback_addr(stub);__ bind(entry->_stub_label);InternalAddress safepoint_pc(masm.pc() - masm.offset() + entry->_safepoint_offset);
#ifdef _LP64__ lea(rscratch1, safepoint_pc);__ movptr(Address(r15_thread, JavaThread::saved_exception_pc_offset()), rscratch1);
#elseconst Register tmp1 = rcx;const Register tmp2 = rdx;__ push(tmp1);__ push(tmp2);__ lea(tmp1, safepoint_pc);__ get_thread(tmp2);__ movptr(Address(tmp2, JavaThread::saved_exception_pc_offset()), tmp1);__ pop(tmp2);__ pop(tmp1);
#endif__ jump(callback_addr);
}
#undef __void C2SafepointPollStubTable::emit(CodeBuffer& cb) {MacroAssembler masm(&cb);for (int i = _safepoints.length() - 1; i >= 0; i--) {// Make sure there is enough space in the code bufferif (cb.insts()->maybe_expand_to_ensure_remaining(PhaseOutput::MAX_inst_size) && cb.blob() == NULL) {ciEnv::current()->record_failure("CodeCache is full");return;}C2SafepointPollStub* entry = _safepoints.at(i);emit_stub(masm, entry);}
}// The selection logic below relieves the need to add dummy files to unsupported platforms.template <bool enabled>typename EnableIf<enabled>::typeselect_emit_stub(MacroAssembler& masm, C2SafepointPollStub* entry) const {emit_stub_impl(masm, entry);}template <bool enabled>typename EnableIf<!enabled>::typeselect_emit_stub(MacroAssembler& masm, C2SafepointPollStub* entry) const {}void emit_stub(MacroAssembler& masm, C2SafepointPollStub* entry) const {select_emit_stub<VM_Version::supports_stack_watermark_barrier()>(masm, entry);}_polling_page_return_handler_blob = generate_handler_blob(CAST_FROM_FN_PTR(address, SafepointSynchronize::handle_polling_page_exception), POLL_AT_RETURN);static SafepointBlob* polling_page_return_handler_blob() { return _polling_page_return_handler_blob; }
##gdb堆棧
(gdb) bt
#0 C2SafepointPollStubTable::emit (this=0x7fffd0bfbb98, cb=...) at /home/yym/openjdk17/jdk17-master/src/hotspot/share/opto/output.cpp:237
#1 0x00007ffff6896363 in PhaseOutput::fill_buffer (this=0x7fffd0bfb950, cb=0x7fffd0bfb970, blk_starts=0x7fffb002a750)at /home/yym/openjdk17/jdk17-master/src/hotspot/share/opto/output.cpp:1824
#2 0x00007ffff6890444 in PhaseOutput::Output (this=0x7fffd0bfb950) at /home/yym/openjdk17/jdk17-master/src/hotspot/share/opto/output.cpp:432
#3 0x00007ffff602fe6b in Compile::Code_Gen (this=0x7fffd0bfde90) at /home/yym/openjdk17/jdk17-master/src/hotspot/share/opto/compile.cpp:2775
#4 0x00007ffff6027214 in Compile::Compile (this=0x7fffd0bfde90, ci_env=0x7fffd0bfeac0, generator=0x7ffff6959ff0 <OptoRuntime::new_instance_Type()>,stub_function=0x7ffff6958c68 <OptoRuntime::new_instance_C(Klass*, JavaThread*)> "\363\017\036\372UH\211\345H\203\354`H\211}\250H\211u\240H\213U\240H\215E\320H\211\326H\211\307\350\067\204N\377H\213M\240H\215E\340\272\001", stub_name=0x7ffff72815ea "_new_instance_Java", is_fancy_jump=0, pass_tls=true, return_pc=false, directive=0x7ffff01b1f90)at /home/yym/openjdk17/jdk17-master/src/hotspot/share/opto/compile.cpp:925
#5 0x00007ffff6958b70 in OptoRuntime::generate_stub (env=0x7fffd0bfeac0, gen=0x7ffff6959ff0 <OptoRuntime::new_instance_Type()>,C_function=0x7ffff6958c68 <OptoRuntime::new_instance_C(Klass*, JavaThread*)> "\363\017\036\372UH\211\345H\203\354`H\211}\250H\211u\240H\213U\240H\215E\320H\211\326H\211\307\350\067\204N\377H\213M\240H\215E\340\272\001", name=0x7ffff72815ea "_new_instance_Java", is_fancy_jump=0, pass_tls=true, return_pc=false)at /home/yym/openjdk17/jdk17-master/src/hotspot/share/opto/runtime.cpp:171
#6 0x00007ffff6958625 in OptoRuntime::generate (env=0x7fffd0bfeac0) at /home/yym/openjdk17/jdk17-master/src/hotspot/share/opto/runtime.cpp:139
#7 0x00007ffff5f07753 in C2Compiler::init_c2_runtime () at /home/yym/openjdk17/jdk17-master/src/hotspot/share/opto/c2compiler.cpp:78
#8 0x00007ffff5f077d7 in C2Compiler::initialize (this=0x7ffff02c01f0) at /home/yym/openjdk17/jdk17-master/src/hotspot/share/opto/c2compiler.cpp:91
#9 0x00007ffff6043287 in CompileBroker::init_compiler_runtime () at /home/yym/openjdk17/jdk17-master/src/hotspot/share/compiler/compileBroker.cpp:1801
#10 0x00007ffff6043806 in CompileBroker::compiler_thread_loop () at /home/yym/openjdk17/jdk17-master/src/hotspot/share/compiler/compileBroker.cpp:1938
#11 0x00007ffff6065c02 in CompilerThread::thread_entry (thread=0x7ffff02c08c0, __the_thread__=0x7ffff02c08c0)at /home/yym/openjdk17/jdk17-master/src/hotspot/share/compiler/compilerThread.cpp:59
#12 0x00007ffff6b5e498 in JavaThread::thread_main_inner (this=0x7ffff02c08c0) at /home/yym/openjdk17/jdk17-master/src/hotspot/share/runtime/thread.cpp:1305
#13 0x00007ffff6b5e32e in JavaThread::run (this=0x7ffff02c08c0) at /home/yym/openjdk17/jdk17-master/src/hotspot/share/runtime/thread.cpp:1288
#14 0x00007ffff6b5ba31 in Thread::call_run (this=0x7ffff02c08c0) at /home/yym/openjdk17/jdk17-master/src/hotspot/share/runtime/thread.cpp:394
#15 0x00007ffff68752bb in thread_native_entry (thread=0x7ffff02c08c0) at /home/yym/openjdk17/jdk17-master/src/hotspot/os/linux/os_linux.cpp:720
#16 0x00007ffff7c94ac3 in start_thread (arg=<optimized out>) at ./nptl/pthread_create.c:442
#17 0x00007ffff7d26850 in clone3 () at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:81
##gdb堆棧
Thread 15 "C1 CompilerThre" hit Breakpoint 1, SharedRuntime::polling_page_return_handler_blob () at /home/yym/openjdk17/jdk17-master/src/hotspot/share/runtime/sharedRuntime.hpp:250
250 static SafepointBlob* polling_page_return_handler_blob() { return _polling_page_return_handler_blob; }
(gdb) bt
#0 SharedRuntime::polling_page_return_handler_blob () at /home/yym/openjdk17/jdk17-master/src/hotspot/share/runtime/sharedRuntime.hpp:250
#1 0x00007ffff5e14d46 in C1SafepointPollStub::emit_code (this=0x7ffff0385490, ce=0x7fffd0afe0f0) at /home/yym/openjdk17/jdk17-master/src/hotspot/cpu/x86/c1_CodeStubs_x86.cpp:104
#2 0x00007ffff5e64987 in LIR_Assembler::emit_stubs (this=0x7fffd0afe0f0, stub_list=0x7fffa409c5f0) at /home/yym/openjdk17/jdk17-master/src/hotspot/share/c1/c1_LIRAssembler.cpp:150
#3 0x00007ffff5e649ff in LIR_Assembler::emit_slow_case_stubs (this=0x7fffd0afe0f0) at /home/yym/openjdk17/jdk17-master/src/hotspot/share/c1/c1_LIRAssembler.cpp:159
#4 0x00007ffff5e19a9d in Compilation::emit_code_epilog (this=0x7fffd0afe4d0, assembler=0x7fffd0afe0f0) at /home/yym/openjdk17/jdk17-master/src/hotspot/share/c1/c1_Compilation.cpp:291
#5 0x00007ffff5e19e18 in Compilation::emit_code_body (this=0x7fffd0afe4d0) at /home/yym/openjdk17/jdk17-master/src/hotspot/share/c1/c1_Compilation.cpp:355
#6 0x00007ffff5e1a12a in Compilation::compile_java_method (this=0x7fffd0afe4d0) at /home/yym/openjdk17/jdk17-master/src/hotspot/share/c1/c1_Compilation.cpp:404
#7 0x00007ffff5e1a470 in Compilation::compile_method (this=0x7fffd0afe4d0) at /home/yym/openjdk17/jdk17-master/src/hotspot/share/c1/c1_Compilation.cpp:460
#8 0x00007ffff5e1ac88 in Compilation::Compilation (this=0x7fffd0afe4d0, compiler=0x7ffff0231910, env=0x7fffd0afe9f0, method=0x7fffa40922b0, osr_bci=-1, buffer_blob=0x7fffe111cf90,install_code=true, directive=0x7ffff01b56b0) at /home/yym/openjdk17/jdk17-master/src/hotspot/share/c1/c1_Compilation.cpp:584
#9 0x00007ffff5e1f184 in Compiler::compile_method (this=0x7ffff0231910, env=0x7fffd0afe9f0, method=0x7fffa40922b0, entry_bci=-1, install_code=true, directive=0x7ffff01b56b0)at /home/yym/openjdk17/jdk17-master/src/hotspot/share/c1/c1_Compiler.cpp:247
#10 0x00007ffff6044f06 in CompileBroker::invoke_compiler_on_method (task=0x7ffff030e790) at /home/yym/openjdk17/jdk17-master/src/hotspot/share/compiler/compileBroker.cpp:2312
#11 0x00007ffff6043a81 in CompileBroker::compiler_thread_loop () at /home/yym/openjdk17/jdk17-master/src/hotspot/share/compiler/compileBroker.cpp:1985
#12 0x00007ffff6065c02 in CompilerThread::thread_entry (thread=0x7ffff02c2340, __the_thread__=0x7ffff02c2340)at /home/yym/openjdk17/jdk17-master/src/hotspot/share/compiler/compilerThread.cpp:59
#13 0x00007ffff6b5e498 in JavaThread::thread_main_inner (this=0x7ffff02c2340) at /home/yym/openjdk17/jdk17-master/src/hotspot/share/runtime/thread.cpp:1305
#14 0x00007ffff6b5e32e in JavaThread::run (this=0x7ffff02c2340) at /home/yym/openjdk17/jdk17-master/src/hotspot/share/runtime/thread.cpp:1288
#15 0x00007ffff6b5ba31 in Thread::call_run (this=0x7ffff02c2340) at /home/yym/openjdk17/jdk17-master/src/hotspot/share/runtime/thread.cpp:394
#16 0x00007ffff68752bb in thread_native_entry (thread=0x7ffff02c2340) at /home/yym/openjdk17/jdk17-master/src/hotspot/os/linux/os_linux.cpp:720
#17 0x00007ffff7c94ac3 in start_thread (arg=<optimized out>) at ./nptl/pthread_create.c:442
#18 0x00007ffff7d26850 in clone3 () at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:81