Javac 位元組碼指令生成
根據标注文法樹進行指令翻譯,将方法中一系列的語句翻譯為 Java 虛拟機能夠執行的一系列指令.
生成位元組碼指令
JVM 在執行 Class 檔案中的位元組碼指令時,會以入棧與出棧的方式執行.
Java 虛拟機會為每個新建立的線程配置設定一個 Java 棧,同時配置設定一個 PC 寄存器,這個 PC 寄存器儲存了 Java 虛拟機正在執行的位元組碼指令的位址。
當調用一個方法時會在這個棧上新建立一個棧桢。
每個棧桢内部都包含一組稱為局部變量表的變量清單,同時還包含一個稱為操作數棧的棧。
Javac 在生成位元組碼指令時盡可能地模拟 Java 虛拟機運作時的過程,用來進行類型驗證及更好地生成位元組碼指令.
實作本地變量表
Javac 在 Code 類中定義了本地變量表,用來模拟 Java 虛拟機運作時的本地變量表。
每個 LocalVar 對象表示一個具體的本地變量
而 nextreg 表示 lvar 數組中下一個可使用的存儲位置,初始值為 0,表示本地變量表存儲的索引位置是從 0 開始的
是以 VarSymbol 類中定義的 adr 變量在位元組碼生成階段儲存的是目前的變量在本地變量表中存儲的索引位置。
實作操作數棧
State 類是定義在 Code 類中的成員類,可以用來模拟操作數棧
com.sun.tools.javac.jvm.Code.State
Type[] stack;
public int stacksize;
在 State 類的構造方法中初始化 stack 數組,預設初始化大小為 16,如果棧的深度逾時 16 還會進行擴容.
stacksize 指的就是目前 stack 數組的大小,由于數組索引是從 0 開始,是以 stacksize-1 就是目前棧的棧頂位置。
為了進行類型校驗,Javac 使用 Type 類型的數組模拟運作時類型的入棧與出棧,這樣就可以在編譯期間發現更多類型相關的錯誤,除此之外還能得出位元組碼指令在運作過程中需要使用的最大棧空間 max_stack 等資訊。
常見的操作操作數棧的一些方法。
1.dup() 方法
dup() 方法可以複制操作數棧
2.push() 方法
push() 方法可以向棧中壓入一個類型
3.pop(Type t) 方法、pop(int n) 方法、pop1() 方法與 pop2() 方法
pop(Type t)、pop(int n)、pop1() 與 pop2() 方法都可以進行彈棧操作
常量池資訊的存儲
Javac 中的 Pool 類代表常量池,可以存儲常量池相關的資訊,為後續 Class 位元組碼檔案中常量池的生成提供必要的資料.
定義在 Pool 類中的常見操作常量池的方法.
1.put() 方法
put() 方法向常量池中放入某個對象并傳回這個對象在常量池中存儲的索引
2.get() 方法
get() 方法可以擷取常量池中某個對象的常量池索引.