jvm詳解-java源碼編譯

來源:互聯網
上載者:User

http://blog.csdn.net/larrylgq/article/details/7395261

java源碼級編譯器的任務是將符合java語言規範的源碼編譯為符合jvm規範的Class檔案,對不符合java語言規範的報錯

在sun的jdk中源碼編譯器是使用java寫的javac

javac的工作流程:

1 解析(parse)和輸入到符號表(enter)

2 註解處理(annotation processing)

3 分析與代碼的產生

解析:

詞法分析:使用com.sun.tools.javac.parser.Scanner類,將代碼字串變為Token序列

eg:

int y = 1;

->Token.INT(name:int)->Token.IDENTIFIER(name:y))+ Token.EQ(name:=))+ Token.INTLITERAL(stringVal:1))+ Token.SEMI(name:;))

文法分析:是一個遞迴下降且運算子優先順序的文法分析器,使用com.sun.tools.javac.parser.Parser類,根據文法由Token序列產生抽象文法樹

eg:

 

 

輸入到符號表

使用com.sun.tools.javac.comp.Enter類,此過程每個編譯單元的抽象文法樹的頂局節點都先被放到待處理列表中並逐個處理列表中的節點

所有的類符號被輸入到外圍範圍的符號表中

確定類的參數(對泛型型別而言)、超類型和介面

如果需要添加預設構造器

將類中出現的符號輸入到類自身的符號表中

分析和檢查代碼中的annotation

 

註解處理:annotation processing

使用com.sun.tools.javac.processing.JavacProcessingEnvironment類,並且支援使用者自訂的annotation

編譯時間lombook對java檔案進行編譯之後會再次進入Parse and Enter步驟

 

標註(Attr)和檢查(Check):

是語義分析的一個步驟,使用com.sun.tools.javac.comp.Attr類和com.sun.tools.javac.comp.Check類

主要作用有:

將文法樹中名字、運算式等元素與變數、方法、類型等聯絡到一起
檢查變數使用前是否已聲明
推導泛型方法的型別參數
檢查類型匹配性
進行常量摺疊(將常量文法樹合并)

資料流分析(Flow)

使用com.sun.tools.javac.comp.Flow類

檢查所有語句都可到達

檢查所有checked exception都被捕獲或拋出
檢查所有局部變數在使用前必項確定性賦值

 檢查有傳回值的方法必須確定性傳回值

檢查變數的確定性且不重複賦值

轉換類型:(TransTypes)

使用com.sun.tools.javac.comp.TransTypes主要作用是將泛型java代碼轉換成普通的java代碼

eg:

List<Integer> list = Arrays.asList(1, 2, 3);
int i = list.get(0);

轉換後:

List list = Arrays.asList(1, 2, 3);
int i = (Integer)list.get(0);為了保證泛型的語義,增加了強制類型轉換

 

解除文法糖:(Lower)

使用com.sun.tools.javac.comp.Lower類

消除if(false){...}形式的無用代碼

將含有文法糖的文法樹改寫為含有簡單語言結構的文法樹

eg

 具名內部類,匿名內部類,類字面量

自動裝箱拆箱

斷言

foreach迴圈

enum或String類型的switch(java7)

eg:

List<Integer> list = Arrays.asList(1, 2, 3);
int i = list.get(0);

轉換後:

List list = Arrays.asList(//自動裝箱拆箱
new Integer[]{
Integer.valueOf(1),
Integer.valueOf(2),
Integer.valueOf(3)
}
);
int i = ((Integer)list.get(0)).intValue();

產生class檔案:(Gen)

使用com.sun.tool.javac.jvm.Gen

將執行個體成員初始化器收集到構造器中成為<init>()
將靜態成員初始化器收集為<clinit>()
從抽象文法樹產生位元組碼
後序遍曆文法樹
進行最後的少量代碼轉換
    String的+操作被產生為StringBuilder操作
    x++/x--在條件允許時被最佳化為++x/--x
    etc …
從符號表產生Class檔案
    產生Class檔案的結構資訊
    產生中繼資料(包括常量池)

class檔案所記錄的資訊

結構資訊

    Class檔案格式版本號碼

    各部分的數量及大小

中繼資料

    類、繼承的超類、實現介面的聲明資訊

    域與方法聲明資訊

    常量池

    使用者自訂的、RetentionPolicy為CLASS或RUNTIME的註解

方法資訊

    位元組碼(程式邏輯)

    異常處理器表

   運算元棧與局部變數區大小

    運算元棧的類型記錄(java6開始 StackMapTable)

    調試用符號資訊(LineNumberTable,LocalVariableTable)

 

class檔案例子:

import java.io.Serializable;
public class Foo implements Serializable {
    public void bar() {
        int i = 31;
        if (i > 0) {
            int j = 42;
        }
    }
}

執行編譯:javac -g Foo.java

執行反編譯:javap -c -s -l -verbose Foo

類聲明:

public class Foo extends java.lang.Object implements java.io.Serializable

源檔案名稱:

SourceFile: "Foo.java"

Class檔案結構資訊:

minor version: 0
major version: 50

常量池:

Constant pool:
const #1 = Method #3.#19; // java/lang/Object."<init>":()V
const #2 = class #20; // Foo
const #3 = class #21; // java/lang/Object
const #4 = class #22; // java/io/Serializable
const #5 = Asciz <init>;
const #6 = Asciz ()V;
const #7 = Asciz Code;
const #8 = Asciz LineNumberTable;
const #9 = Asciz LocalVariableTable;
const #10 = Asciz this;
const #11 = Asciz LFoo;;
const #12 = Asciz bar;
const #13 = Asciz j;
const #14 = Asciz I;
const #15 = Asciz i;
const #16 = Asciz StackMapTable;
const #17 = Asciz SourceFile;
const #18 = Asciz Foo.java;
const #19 = NameAndType #5:#6;// "<init>":()V
const #20 = Asciz Foo;
const #21 = Asciz java/lang/Object;
const #22 = Asciz java/io/Serializable;//引入包時使用*通配,從Class檔案來看沒有任何不同,只不過使用萬用字元增加了源碼中名字衝突的可能性而已。

方法中繼資料:

public Foo();
    Signature: ()V
    LineNumberTable:
        line 2: 0
    LocalVariableTable:
        Start Length Slot Name Signature
        0 5 0 this LFoo;
    Code:
        Stack=1, Locals=1, Args_size=1

位元組碼:

0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return

方法中繼資料:

public void bar();
    Signature: ()V
    LineNumberTable:
        line 4: 0
        line 5: 3
        line 6: 7
        line 8: 10
    LocalVariableTable:                        // 參數名跟局部變數名都儲存在LocalVariableTable;返個屬性工作表跟方法體聯絡在一起,而介面的方法沒有方法體,
    Start Length Slot Name Signature //所以ASM無法從介面類型上的方法取得參數的名稱
    10 0 2 j I
    0 11 0 this LFoo;
    3 8 1 i I
StackMapTable: number_of_entries = 1
    frame_type = 252 /* append */
        offset_delta = 10
        locals = [ int ]
Code:
Stack=1, Locals=3, Args_size=1

位元組碼:

0: bipush 31
2: istore_1
3: iload_1
4: ifle 10
7: bipush 42
9: istore_2
10: return

 

Class檔案與jdk版本比較

JDK版本Class檔案版本(major.minor)
1.0 --------45.3
1.1 --------45.3
1.2 --------46.0
1.3 --------47.0
1.4 --------48.0
5    --------49.0
6    --------50.0
7    --------51.0

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.