V8引擎是如何為JS中的函數分配地址(或任意除了函數名外能夠標識函數的變數)的?

我想得到V8引擎在解析JavaScript時為JS中的函數所分配的地址(或者任何一個除了函數名外能夠唯一的標識JS中的函數的變數,比如函數指針、標識符什麼的)。我在V8源碼的http://parser.cc文件中找了幾個可能的變數(positionstack,functionid等),用GDB動態調試,結果都不是我想要的。我希望能夠找到這樣一個為JS中的函數分配地址的函數,在此設斷點,然後每次觸發JS中的函數時,程序能夠在該斷點處停下,獲取將要執行的函數的地址,請問各位有沒有相關的經驗?不勝感激!


更新:題主在評論里給了更具體的用例,我把針對那個用例涉及的知識更新到這個回答的後面。

下面先放原本的回答:

題主的問題里隱含著一些假設:

我希望能夠找到這樣一個為JS中的函數分配地址的函數,在此設斷點,然後每次觸發JS中的函數時,程序能夠在該斷點處停下,獲取將要執行的函數的地址

但是怎樣算是「觸發一個JS中的函數」?我只能假設題主想要的是「每當V8為一個JavaScript函數編譯生成可執行代碼」,然後要拿的「地址」是編譯出來的機器碼的起始地址。

(但題主想要的未必是這個。歡迎在評論里說明具體要所的是什麼事情。)

那樣的話好辦。V8里有多個JIT編譯器,它們都可以把JavaScript函數編譯為機器碼:

  • Full Codegen(初級編譯器)
  • Optimizing Compiler(優化編譯器,Hydrogen+Lithium)
  • Turbofan(更優化編譯器)

還有Irregexp(正則表達式編譯器),不過這裡先不討論它。

V8並不只是第一次執行一個JavaScript函數時才編譯它;同一個JavaScript函數可以被這些JIT編譯器多次編譯。

當前默認的流程是:

[JavaScript函數] -&>
第一次被調用時 -&> Full Codegen -&> [初級編譯後的代碼]
足夠熱之後 -&> Optimizing Compiler -&> [優化編譯後的代碼]
如果優化的代碼需要去優化 -&> deoptimize -&> 回到[初級編譯後的代碼]
... 周而復始 ...

Turbofan目前還是一個實驗性編譯器,默認不參與編譯。

引用Vyacheslav Egorov的一張圖:

要捕獲這些編譯器的編譯結果,其實好多地方都可以,例如:

一個是:src/codegen.cc

void CodeGenerator::PrintCode(Handle& code, CompilationInfo* info)

V8的所有JIT編譯器都會調用這個函數來列印編譯結果的日誌。在它的開頭設個斷點,看看Code的內容即可。

Code::entry() / Code::instruction_start()就是生成的機器碼的起始地址。

另一個也是類似的:src/compiler.h

void CompilationInfo::SetCode(Handle& code)

JIT編譯器在生成好代碼後,最終要把代碼「安裝」到系統里。這個SetCode()是必經之路。不過它是個小函數,很可能在編譯出來之後被內聯(inline)到調用者那邊了,所以不一定適合放斷點。

=======================================================

題主在評論里補充的用例是:

比如這樣:

&
function f1() {
alert("f1")
}
function f2(){
alert("f2")
}
f1();
f2();
f1();
&

我希望設的斷點的效果是,當頁面解析至這個script時,停在斷點,列印f1()的地址;continue,停在斷點,列印f2()的地址; continue, 停在斷點,列印f1()的地址。


推薦閱讀:

(2017)你最不建議使用的Python Web框架?
如何評價Github的新版黑色Header?
既然Tengine比Nginx更強大,為什麼沒有取代Nginx呢?
有哪些python+flask的搭建的博客或論壇開源推薦?
有哪些好用的前端開發軟體?

TAG:Web開發 | JavaScript | V8 | JavaScript引擎 |