日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 综合教程 >内容正文

综合教程

触发OSR 编译(以goto指令为例)及安装与卸载

發布時間:2024/1/4 综合教程 28 生活家
生活随笔 收集整理的這篇文章主要介紹了 触发OSR 编译(以goto指令为例)及安装与卸载 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

流程圖如下。

決定一個方法是否為熱點代碼的因素有兩個:方法的調用次數、循環回邊的執行次數。即時編譯便是根據這兩個計數器的和來觸發的。為什么 Java 虛擬機需要維護兩個不同的計數器呢?

實際上,除了以方法為單位的即時編譯之外,Java 虛擬機還存在著另一種以循環為單位的即時編譯,叫做 On-Stack-Replacement(OSR)編譯。循環回邊計數器便是用來觸發這種類型的編譯的。

OSR 實際上是一種技術,它指的是在程序執行過程中,動態地替換掉 Java 方法棧楨,從而使得程序能夠在非方法入口處進行解釋執行和編譯后的代碼之間的切換。事實上,去優化(deoptimization)采用的技術也可以稱之為 OSR。

在不啟用分層編譯的情況下,觸發 OSR 編譯的閾值是由參數 -XX:CompileThreshold 指定的閾值的倍數。

該倍數的計算方法為:

(OnStackReplacePercentage - InterpreterProfilePercentage)/100

其中 -XX:InterpreterProfilePercentage 的默認值為 33,當使用 C1 時 -XX:OnStackReplacePercentage 為 933,當使用 C2 時為 140。

也就是說,默認情況下,C1 的 OSR 編譯的閾值為 13500,而 C2 的為 10700。

在啟用分層編譯的情況下,觸發 OSR 編譯的閾值則是由參數 -XX:TierXBackEdgeThreshold 指定的閾值乘以系數。

OSR 編譯在正常的應用程序中并不多見。它只在基準測試時比較常見,因此并不需要過多了解。

通過調用TemplateTable::_goto()函數來完成goto()指令的機器代碼生成。如下:

// 將當前棧幀中保存的Method* 拷貝到rcx中
0x00007fffe101dd10: mov    -0x18(%rbp),%rcx
// 如果開啟了profile則執行分支跳轉相關的性能統計
// If no method data exists, go to profile_continue.
// Otherwise, assign to mdp


0x00007fffe101dd14: mov    -0x20(%rbp),%rax
0x00007fffe101dd18: test   %rax,%rax
0x00007fffe101dd1b: je     0x00007fffe101dd39
// 將JumpData::taken_off_set存儲到%rax中


0x00007fffe101dd21: mov    0x8(%rax),%rbx
// 增加DataLayout::counter_increment,值為1
0x00007fffe101dd25: add    $0x1,%rbx
// sbb是帶借位減法指令
0x00007fffe101dd29: sbb    $0x0,%rbx
// 存儲回JumpData::taken_off_set中
0x00007fffe101dd2d: mov    %rbx,0x8(%rax)

// The method data pointer needs to be updated to reflect the new target.
// 將JumpData::displacement_off_set
// %rax中存儲的是MethodData*
0x00007fffe101dd31: add    0x10(%rax),%rax
// 將計算出的值存儲到棧中interpreter_frame_mdx_offset偏向處
0x00007fffe101dd35: mov    %rax,-0x20(%rbp)

// **** profile_continue ****

// 將當前字節碼位置往后偏移1字節處開始的2字節數據讀取到rdx中

0x00007fffe101dd39: movswl 0x1(%r13),%edx
// 將rdx中的值字節次序變反
0x00007fffe101dd3e: bswap  %edx
// 將rdx中的值右移16位,上述兩步就是為了計算跳轉分支的偏移量
0x00007fffe101dd40: sar    $0x10,%edx
// 將rdx中的數據從2字節擴展成4字節
0x00007fffe101dd43: movslq %edx,%rdx
// 將當前字節碼地址加上rdx保存的偏移量,計算跳轉的目標地址
0x00007fffe101dd46: add    %rdx,%r13

如果UseLoopCounter為true時才會有如下匯編,在執行如下匯編時,各個寄存器的狀態如下:

increment backedge counter for backward branches

rax: MDO
ebx: MDO bumped taken-count
rcx: method
rdx: target offset
r13: target bcp
r14: locals pointer

匯編如下:  

// 校驗rdx是否大于0,如果大于0說明是往前跳轉,如果小于0說明是往后跳轉,如果大于0則跳轉到dispatch,這樣只有回邊才會進行統計
0x00007fffe101dd49: test   %edx,%edx
0x00007fffe101dd4b: jns    0x00007fffe101de30  // 跳轉到dispatch

// 執行這里時,說明有回邊需要統計
// 檢查Method::_method_counters是否為NULL,如果非空則跳轉到has_counters
0x00007fffe101dd51: mov    0x20(%rcx),%rax
0x00007fffe101dd55: test   %rax,%rax
0x00007fffe101dd58: jne    0x00007fffe101ddf4

// 如果為空,則通過InterpreterRuntime::build_method_counters()函數創建一個新的MethodCounters
0x00007fffe101dd5e: push   %rdx
0x00007fffe101dd5f: push   %rcx
0x00007fffe101dd60: callq  0x00007fffe101dd6a
0x00007fffe101dd65: jmpq   0x00007fffe101dde8
0x00007fffe101dd6a: mov    %rcx,%rsi
0x00007fffe101dd6d: lea    0x8(%rsp),%rax
0x00007fffe101dd72: mov    %r13,-0x38(%rbp)
0x00007fffe101dd76: mov    %r15,%rdi
0x00007fffe101dd79: mov    %rbp,0x200(%r15)
0x00007fffe101dd80: mov    %rax,0x1f0(%r15)
0x00007fffe101dd87: test   $0xf,%esp
0x00007fffe101dd8d: je     0x00007fffe101dda5
0x00007fffe101dd93: sub    $0x8,%rsp
0x00007fffe101dd97: callq  0x00007ffff66b581c
0x00007fffe101dd9c: add    $0x8,%rsp
0x00007fffe101dda0: jmpq   0x00007fffe101ddaa
0x00007fffe101dda5: callq  0x00007ffff66b581c
0x00007fffe101ddaa: movabs $0x0,%r10
0x00007fffe101ddb4: mov    %r10,0x1f0(%r15)
0x00007fffe101ddbb: movabs $0x0,%r10
0x00007fffe101ddc5: mov    %r10,0x200(%r15)
0x00007fffe101ddcc: cmpq   $0x0,0x8(%r15)
0x00007fffe101ddd4: je     0x00007fffe101dddf
0x00007fffe101ddda: jmpq   0x00007fffe1000420
0x00007fffe101dddf: mov    -0x38(%rbp),%r13
0x00007fffe101dde3: mov    -0x30(%rbp),%r14
0x00007fffe101dde7: retq   
0x00007fffe101dde8: pop    %rcx
0x00007fffe101dde9: pop    %rdx
// 將創建出新的MethodCounters存儲到%rax中
0x00007fffe101ddea: mov    0x20(%rcx),%rax
//如果創建失敗,則跳轉到到dispatch分支
0x00007fffe101ddee: je     0x00007fffe101de30

// ....

  

如下在啟動分層編譯時才會生成的匯編:

// **** has_counters ****
// 開啟profile性能收集才會生成的匯編
// 獲取Method::_method_data屬性到rbx中,并校驗其是否為空,如果為空則跳轉到no_mdo
0x00007fffe101ddf4: mov    0x18(%rcx),%rbx
0x00007fffe101ddf8: test   %rbx,%rbx
0x00007fffe101ddfb: je     0x00007fffe101de17

//Method::_method_data屬性不為空,則增加Method::_method_data::_backedge_counter計數值,如果超過閾值則跳轉到backedge_counter_overflow
0x00007fffe101ddfd: mov    0x70(%rbx),%eax
0x00007fffe101de00: add    $0x8,%eax
0x00007fffe101de03: mov    %eax,0x70(%rbx)
0x00007fffe101de06: and    $0x1ff8,%eax
0x00007fffe101de0c: je     0x00007fffe101df22 // 跳轉到backedge_counter_overflow
// 跳轉到dispatch
0x00007fffe101de12: jmpq   0x00007fffe101de30

// **** no_mdo ****
 // 增加Method::_method_counters::backedge_counter的調用計數,如果超過閾值則跳轉到backedge_counter_overflow

0x00007fffe101de17: mov    0x20(%rcx),%rcx
0x00007fffe101de1b: mov    0xc(%rcx),%eax
0x00007fffe101de1e: add    $0x8,%eax
0x00007fffe101de21: mov    %eax,0xc(%rcx)
0x00007fffe101de24: and    $0x1ff8,%eax
0x00007fffe101de2a: je     0x00007fffe101df22 // 跳轉到backedge_counter_overflow


// **** dispatch ****
 // r13已經變成目標跳轉地址,這里是加載跳轉地址的第一個字節碼到rbx中
0x00007fffe101de30: movzbl 0x0(%r13),%ebx
0x00007fffe101de35: movabs $0x7ffff73b9e40,%r10
0x00007fffe101de3f: jmpq   *(%r10,%rbx,8)

// **** profile_method ****
// 通過call_VM()函數來調用InterpreterRuntime::profile_method()函數
0x00007fffe101de43: callq  0x00007fffe101de4d
0x00007fffe101de48: jmpq   0x00007fffe101dec8
0x00007fffe101de4d: lea    0x8(%rsp),%rax
0x00007fffe101de52: mov    %r13,-0x38(%rbp)
0x00007fffe101de56: mov    %r15,%rdi
0x00007fffe101de59: mov    %rbp,0x200(%r15)
0x00007fffe101de60: mov    %rax,0x1f0(%r15)
0x00007fffe101de67: test   $0xf,%esp
0x00007fffe101de6d: je     0x00007fffe101de85
0x00007fffe101de73: sub    $0x8,%rsp
0x00007fffe101de77: callq  0x00007ffff66b4d84
0x00007fffe101de7c: add    $0x8,%rsp
0x00007fffe101de80: jmpq   0x00007fffe101de8a
0x00007fffe101de85: callq  0x00007ffff66b4d84
0x00007fffe101de8a: movabs $0x0,%r10
0x00007fffe101de94: mov    %r10,0x1f0(%r15)
0x00007fffe101de9b: movabs $0x0,%r10
0x00007fffe101dea5: mov    %r10,0x200(%r15)
0x00007fffe101deac: cmpq   $0x0,0x8(%r15)
0x00007fffe101deb4: je     0x00007fffe101debf
0x00007fffe101deba: jmpq   0x00007fffe1000420
0x00007fffe101debf: mov    -0x38(%rbp),%r13
0x00007fffe101dec3: mov    -0x30(%rbp),%r14
0x00007fffe101dec7: retq   
// 結束call_VM()函數結束

// 調用set_method_data_pointer_for_bcp()函數生成的匯編
// restore target bytecode
0x00007fffe101dec8: movzbl 0x0(%r13),%ebx
0x00007fffe101decd: push   %rax
0x00007fffe101dece: push   %rbx

// 獲取Method::_method_data并存儲到%rax中
0x00007fffe101decf: mov    -0x18(%rbp),%rbx
0x00007fffe101ded3: mov    0x18(%rbx),%rax
// 如果Method::_method_data為NULL,則跳轉到set_mdp
0x00007fffe101ded7: test   %rax,%rax
0x00007fffe101deda: je     0x00007fffe101df17

// 通過call_VM_leaf()函數調用InterpreterRuntime::bcp_to_di()函數
0x00007fffe101dee0: mov    %r13,%rsi
0x00007fffe101dee3: mov    %rbx,%rdi
0x00007fffe101dee6: test   $0xf,%esp
0x00007fffe101deec: je     0x00007fffe101df04
0x00007fffe101def2: sub    $0x8,%rsp
0x00007fffe101def6: callq  0x00007ffff66b4bb4
0x00007fffe101defb: add    $0x8,%rsp
0x00007fffe101deff: jmpq   0x00007fffe101df09
0x00007fffe101df04: callq  0x00007ffff66b4bb4

// rax: mdi
// mdo is guaranteed to be non-zero here, we checked for it before the call.

// 將Method::_method_data存儲到%rbx中
0x00007fffe101df09: mov    0x18(%rbx),%rbx
// 增加Method::_method_data::_data偏移
0x00007fffe101df0d: add    $0x90,%rbx
0x00007fffe101df14: add    %rbx,%rax
// **** set_mdp ****
// 通過interpreter_frame_mdx_offset來獲取mdx
0x00007fffe101df17: mov    %rax,-0x20(%rbp)
0x00007fffe101df1b: pop    %rbx
0x00007fffe101df1c: pop    %rax
// 結束set_method_data_pointer_for_bcp()函數調用
0x00007fffe101df1d: jmpq   0x00007fffe101de30

調用的InterpreterRuntime::profile_method()函數的實現如下:

IRT_ENTRY(void, InterpreterRuntime::profile_method(JavaThread* thread))
  // use UnlockFlagSaver to clear and restore the _do_not_unlock_if_synchronized
  // flag, in case this method triggers classloading which will call into Java.
  UnlockFlagSaver fs(thread);

  assert(ProfileInterpreter, "must be profiling interpreter");
  frame  fr = thread->last_frame();
  assert(fr.is_interpreted_frame(), "must come from interpreter");
  methodHandle  method(thread, fr.interpreter_frame_method());
  Method::build_interpreter_method_data(method, THREAD);
IRT_END

// Build a MethodData* object to hold information about this method
// collected in the interpreter.
void Method::build_interpreter_method_data(methodHandle method, TRAPS) {
  // Do not profile method if current thread holds the pending list lock,
  // which avoids deadlock for acquiring the MethodData_lock.
  if (InstanceRefKlass::owns_pending_list_lock((JavaThread*)THREAD)) {
    return;
  }

  // Grab a lock here to prevent multiple MethodData*s from being created.
  MutexLocker ml(MethodData_lock, THREAD);
  if (method->method_data() == NULL) {
    ClassLoaderData* loader_data = method->method_holder()->class_loader_data();
    MethodData* method_data = MethodData::allocate(loader_data, method, CHECK);
    method->set_method_data(method_data);
  }
}

就是為Method::_method_data屬性創建MethodData對象并賦值。  

// 只有開啟UseOnStackReplacement時才會生成如下匯編
// 當超過閾值后會跳轉到此分支
// **** backedge_counter_overflow ****
// 對rdx中的數取補碼
0x00007fffe101df22: neg    %rdx
// 將r13的地址加到rdx上,這兩步是計算跳轉地址
0x00007fffe101df25: add    %r13,%rdx

// 通過調用call_VM()函數來調用InterpreterRuntime::frequency_counter_overflow()函數
0x00007fffe101df28: callq  0x00007fffe101df32
0x00007fffe101df2d: jmpq   0x00007fffe101dfb0
0x00007fffe101df32: mov    %rdx,%rsi
0x00007fffe101df35: lea    0x8(%rsp),%rax
0x00007fffe101df3a: mov    %r13,-0x38(%rbp)
0x00007fffe101df3e: mov    %r15,%rdi
0x00007fffe101df41: mov    %rbp,0x200(%r15)
0x00007fffe101df48: mov    %rax,0x1f0(%r15)
0x00007fffe101df4f: test   $0xf,%esp
0x00007fffe101df55: je     0x00007fffe101df6d
0x00007fffe101df5b: sub    $0x8,%rsp
0x00007fffe101df5f: callq  0x00007ffff66b45c8
0x00007fffe101df64: add    $0x8,%rsp
0x00007fffe101df68: jmpq   0x00007fffe101df72
0x00007fffe101df6d: callq  0x00007ffff66b45c8
0x00007fffe101df72: movabs $0x0,%r10
0x00007fffe101df7c: mov    %r10,0x1f0(%r15)
0x00007fffe101df83: movabs $0x0,%r10
0x00007fffe101df8d: mov    %r10,0x200(%r15)
0x00007fffe101df94: cmpq   $0x0,0x8(%r15)
0x00007fffe101df9c: je     0x00007fffe101dfa7
0x00007fffe101dfa2: jmpq   0x00007fffe1000420
0x00007fffe101dfa7: mov    -0x38(%rbp),%r13
0x00007fffe101dfab: mov    -0x30(%rbp),%r14
0x00007fffe101dfaf: retq  
// 結束call_VM()函數的調用

// 恢復待執行的字節碼 
0x00007fffe101dfb0: movzbl 0x0(%r13),%ebx
// rax: osr nmethod (osr ok) or NULL (osr not possible)
// ebx: target bytecode
// rdx: scratch
// r14: locals pointer
// r13: bcp
// 校驗frequency_counter_overflow()函數返回的編譯結果是否為空,如果為空則跳轉到dispatch,即繼續執行字節碼
0x00007fffe101dfb5: test   %rax,%rax
0x00007fffe101dfb8: je     0x00007fffe101de30

// 如果不為空,即表示方法編譯完成,將nmethod::_entry_bci屬性的偏移復制到rcx中
0x00007fffe101dfbe: mov    0x48(%rax),%ecx
 // 如果rcx等于InvalidOSREntryBci,則跳轉到dispatch
0x00007fffe101dfc1: cmp    $0xfffffffe,%ecx
0x00007fffe101dfc4: je     0x00007fffe101de30

// 開始執行棧上替換
// We have the address of an on stack replacement routine in eax
// We need to prepare to execute the OSR method. First we must
// migrate the locals and monitors off of the stack.

0x00007fffe101dfca: mov    %rax,%r13 // save the nmethod

// 通過調用call_VM()函數調用SharedRuntime::OSR_migration_begin()函數
// // 調用OSR_migration_begin方法,完成棧幀上變量和monitor的遷移
0x00007fffe101dfcd: callq  0x00007fffe101dfd7
0x00007fffe101dfd2: jmpq   0x00007fffe101e052
0x00007fffe101dfd7: lea    0x8(%rsp),%rax
0x00007fffe101dfdc: mov    %r13,-0x38(%rbp)
0x00007fffe101dfe0: mov    %r15,%rdi
0x00007fffe101dfe3: mov    %rbp,0x200(%r15)
0x00007fffe101dfea: mov    %rax,0x1f0(%r15)
0x00007fffe101dff1: test   $0xf,%esp
0x00007fffe101dff7: je     0x00007fffe101e00f
0x00007fffe101dffd: sub    $0x8,%rsp
0x00007fffe101e001: callq  0x00007ffff6a18a6a
0x00007fffe101e006: add    $0x8,%rsp
0x00007fffe101e00a: jmpq   0x00007fffe101e014
0x00007fffe101e00f: callq  0x00007ffff6a18a6a
0x00007fffe101e014: movabs $0x0,%r10
0x00007fffe101e01e: mov    %r10,0x1f0(%r15)
0x00007fffe101e025: movabs $0x0,%r10
0x00007fffe101e02f: mov    %r10,0x200(%r15)
0x00007fffe101e036: cmpq   $0x0,0x8(%r15)
0x00007fffe101e03e: je     0x00007fffe101e049
0x00007fffe101e044: jmpq   0x00007fffe1000420
0x00007fffe101e049: mov    -0x38(%rbp),%r13
0x00007fffe101e04d: mov    -0x30(%rbp),%r14
0x00007fffe101e051: retq   

// eax is OSR buffer, move it to expected parameter location
// 將rax中的值拷貝到%rsi(j_rarg0)

0x00007fffe101e052: mov    %rax,%rsi
// 獲取interpreter_frame_sender_sp_offset偏移處的值
0x00007fffe101e055: mov    -0x8(%rbp),%rdx
0x00007fffe101e059: leaveq           // remove frame anchor
0x00007fffe101e05a: pop    %rcx      // get return address
0x00007fffe101e05b: mov    %rdx,%rsp // set sp to sender sp
// Ensure compiled code always sees stack at proper alignment
// -StackAlignmentInBytes為$0xfffffffffffffff0


0x00007fffe101e05e: and    $0xfffffffffffffff0,%rsp
// unlike x86 we need no specialized return from compiled code to the interpreter or the call stub.
// push the return address
0x00007fffe101e062: push   %rcx
// 跳轉到nmethod::_osr_entry_point,開始執行
0x00007fffe101e063: jmpq   *0x88(%r13)  

調用的SharedRuntime::OSR_migration_begin()函數的實現如下:

// OSR Migration Code
//
// This code is used convert interpreter frames into compiled frames.  It is
// called from very start of a compiled OSR nmethod.  A temp array is
// allocated to hold the interesting bits of the interpreter frame.  All
// active locks are inflated to allow them to move.  The displaced headers and
// active interpeter locals are copied into the temp buffer.  Then we return
// back to the compiled code.  The compiled code then pops the current
// interpreter frame off the stack and pushes a new compiled frame.  Then it
// copies the interpreter locals and displaced headers where it wants.
// Finally it calls back to free the temp buffer.
//
// All of this is done NOT at any Safepoint, nor is any safepoint or GC allowed.

// 調用OSR_migration_begin方法,完成棧幀上變量和monitor的遷移
JRT_LEAF(intptr_t*, SharedRuntime::OSR_migration_begin( JavaThread *thread) )

  // This code is dependent on the memory layout of the interpreter local
  // array and the monitors. On all of our platforms the layout is identical
  // so this code is shared. If some platform lays the their arrays out
  // differently then this code could move to platform specific code or
  // the code here could be modified to copy items one at a time using
  // frame accessor methods and be platform independent.

  frame fr = thread->last_frame();
  assert( fr.is_interpreted_frame(), "" );
  assert( fr.interpreter_frame_expression_stack_size()==0, "only handle empty stacks" );

  // Figure out how many monitors are active.
  int active_monitor_count = 0;
  for(
	   BasicObjectLock *kptr = fr.interpreter_frame_monitor_end();
       kptr < fr.interpreter_frame_monitor_begin();
       kptr = fr.next_monitor_in_interpreter_frame(kptr)
  ) {
      if( kptr->obj() != NULL ) {
    	  active_monitor_count++;
      }
  }

  // QQQ we could place number of active monitors in the array so that compiled code
  // could double check it.

  Method* moop = fr.interpreter_frame_method();
  int max_locals = moop->max_locals();
  // Allocate temp buffer, 1 word per local & 2 per active monitor
  int buf_size_words = max_locals + active_monitor_count*2;
  intptr_t *buf = NEW_C_HEAP_ARRAY(intptr_t,buf_size_words, mtCode);

  // Copy the locals.  Order is preserved so that loading of longs works.
  // Since there's no GC I can copy the oops blindly.
  assert( sizeof(HeapWord)==sizeof(intptr_t), "fix this code");
  Copy::disjoint_words((HeapWord*)fr.interpreter_frame_local_at(max_locals-1),
                       (HeapWord*)&buf[0],
                       max_locals);

  // Inflate locks.  Copy the displaced headers.  Be careful, there can be holes.
  int i = max_locals;
  for(
	   BasicObjectLock *kptr2 = fr.interpreter_frame_monitor_end();
       kptr2 < fr.interpreter_frame_monitor_begin();
       kptr2 = fr.next_monitor_in_interpreter_frame(kptr2)
  ){
     if( kptr2->obj() != NULL) {         // Avoid 'holes' in the monitor array
        BasicLock *lock = kptr2->lock();
        // Inflate so the displaced header becomes position-independent,什么意思??
        if (lock->displaced_header()->is_unlocked()){ // 無鎖狀態
           ObjectSynchronizer::inflate_helper(kptr2->obj()); // 將鎖對象膨脹為重量級鎖
        }

        // Now the displaced header is free to move
        buf[i++] = (intptr_t)lock->displaced_header();
        buf[i++] = cast_from_oop<intptr_t>(kptr2->obj());
     }
  }
  assert( i - max_locals == active_monitor_count*2, "found the expected number of monitors" );

  return buf;
JRT_END

  

調用InstanceKlass::add_osr_nmethod()與InstanceKlass::remove_osr_nmethod()對OSR進行安裝與卸載。

add_osr_nmethod用于將需要執行棧上替換的nmethod實例插入到InstanceKlass的osr_nmethods鏈表上,方法實現如下:

void InstanceKlass::add_osr_nmethod(nmethod* n) {
  // 獲取鎖
  OsrList_lock->lock_without_safepoint_check();
  //校驗必須是棧上替換方法
  assert(n->is_osr_method(), "wrong kind of nmethod");
  // 將_osr_nmethods_head設置成n的下一個方法
  n->set_osr_link(osr_nmethods_head());
  // 將n設置為_osr_nmethods_head
  set_osr_nmethods_head(n);
  // 如果使用分層編譯
  if (TieredCompilation) {
    Method* m = n->method();
    // 更新最高編譯級別
    m->set_highest_osr_comp_level(MAX2(m->highest_osr_comp_level(), n->comp_level()));
  }
  // 解鎖
  OsrList_lock->unlock();
 
  // Get rid of the osr methods for the same bci that have lower levels.
  if (TieredCompilation) {
    // 查找所有低于nmethod的編譯級別的屬于同一方法的nmethod實例,將其從osr_nmethods鏈表上移除
    for (int l = CompLevel_limited_profile; l < n->comp_level(); l++) {
      nmethod *inv = lookup_osr_nmethod(n->method(), n->osr_entry_bci(), l, true);
      if (inv != NULL && inv->is_in_use()) {
          inv->make_not_entrant();
      }
    }
  }
}
 
nmethod* osr_nmethods_head() const { return _osr_nmethods_head; };

與add_osr_nmethod相對應的就是remove_osr_nmethod,用于從osr_nmethod鏈表上移除nmethod,當nmethod被標記成not_entrant或者zombie時,或者執行CodeCache垃圾回收時會調用該方法,其源碼說明如下:

void InstanceKlass::remove_osr_nmethod(nmethod* n) {
  // 獲取鎖
  OsrList_lock->lock_without_safepoint_check();
  // 校驗是否棧上替換方法
  assert(n->is_osr_method(), "wrong kind of nmethod");
  nmethod* last = NULL;
  // 獲取osr_nmethods鏈表的頭元素
  nmethod* cur  = osr_nmethods_head();
  int max_level = CompLevel_none;  // Find the max comp level excluding n
  Method* m = n->method();
  // 遍歷osr_nmethods鏈表直到遇到n,找到n所屬的方法的所有nmehtod的最高編譯級別
  while(cur != NULL && cur != n) {
    if (TieredCompilation && m == cur->method()) {
      // Find max level before n
      max_level = MAX2(max_level, cur->comp_level());
    }
    last = cur;
    cur = cur->osr_link();
  }
  nmethod* next = NULL;
  // 如果從鏈表中找到了目標nmethod
  if (cur == n) {
    // 將目標nmethod從鏈表中移除
    next = cur->osr_link();
    if (last == NULL) {
      // Remove first element
      set_osr_nmethods_head(next);
    } else {
      last->set_osr_link(next);
    }
  }
  n->set_osr_link(NULL);
  if (TieredCompilation) {
    cur = next;
    // 遍歷鏈表,更新最大編譯級別
    while (cur != NULL) {
      // Find max level after n
      if (m == cur->method()) {
        max_level = MAX2(max_level, cur->comp_level());
      }
      cur = cur->osr_link();
    }
    m->set_highest_osr_comp_level(max_level);
  }
  // Remember to unlock again
  OsrList_lock->unlock();
}

 

參考文章:

(1)HotSpot中執行引擎技術詳解(四)——hotspot探測

(2)下載The Java HotSpot Server Compiler論文

(3)Hotspot 熱點代碼編譯和棧上替換 源碼解析

(4)[討論][HotSpot VM] JIT編譯以及執行native code的流程

  

總結

以上是生活随笔為你收集整理的触发OSR 编译(以goto指令为例)及安装与卸载的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 亚洲人午夜射精精品日韩 | 韩国三级国产 | 一卡二卡三卡在线 | 日韩av网址在线观看 | 99ri国产在线 | 午夜成年人视频 | 久久97视频 | 欧美特级aaa | 肉丝肉足丝袜一区二区三区 | 干夜夜| 午夜裸体性播放 | 国产suv精品一区二区 | 在线免费av网 | 日韩av在线一区二区三区 | 男生草女生视频 | 男生插女生的视频 | 麻豆91在线| 日本在线视频免费观看 | 欧美性极品少妇xxxx | 韩国成年人网站 | 日韩激情在线视频 | 波多野一区 | 性色影院| 亚洲爱视频 | 亚洲黄色免费电影 | 激情小说亚洲色图 | 99热这里精品 | 精品国产一区二区三区日日嗨 | 阿v视频在线免费观看 | 成人a在线 | 日日躁狠狠躁 | 日韩美女免费视频 | 日本激情小视频 | 岛国毛片在线观看 | 福利一二三区 | 91福利一区 | 久久婷婷六月 | www.av小说| 国产在线一区二 | 奇米影视四色7777 | 欧美怡春院 | 久久色婷婷 | 五月婷婷六月综合 | 800av免费在线观看 | 伊人天堂av | 日韩一区二区精品视频 | 亚洲精品水蜜桃 | 日本成人精品 | sm捆绑调教视频 | 午夜视频在线观看免费视频 | av在线视| 日韩一区二区三区在线播放 | 亚洲欧洲久久 | 韩国三级hd中文字幕有哪些 | 91丨国产丨捆绑调教 | 亚洲精品在线播放视频 | 91高清免费视频 | 国产区亚洲区 | 公车乳尖揉捏酥软呻吟 | 日韩色黄大片 | 激情91 | 久久久久人妻一区精品色欧美 | 天天色天 | 国产免费黄色片 | 国产成人免费网站 | 欧美人一级淫片a免费播放 西方av在线 | 麻豆一区二区三区在线观看 | 人妻少妇精品视频一区二区三区 | 成年人网站在线 | 99热99re6国产在线播放 | 99cao| 免费看一区二区三区 | 91麻豆一区二区三区 | 亚洲区精品 | 国产v综合v亚洲欧美久久 | 欧美日韩另类一区 | 伊人色区 | 泰坦尼克号3小时49分的观看方法 | 91插插视频 | www.av麻豆 | free国产hd露脸性开放 | 中文字幕在线观看视频www | 女人扒开腿让男人桶爽 | 成人国产片女人爽到高潮 | va在线看| 亚洲人在线观看 | 精品无码人妻一区二区三区品 | 污视频在线观看网站 | 成人亚洲国产 | 欧美色婷婷 | 丁香婷婷综合网 | 黄色成人毛片 | 国产一区二区三区免费看 | 欧美一级片免费看 | 成人教育av | 成年人免费小视频 | 美女av影院 | 国产吃瓜在线 | 麻豆视频在线免费观看 |