1. 引言
??? 眾所周知,Java語(yǔ)言依靠Java虛擬機(jī)對(duì)字節(jié)碼程序的支持,實(shí)現(xiàn)了跨平臺(tái)特征。作為一種中間語(yǔ)言,Java字節(jié)碼提供了匯編指令級(jí)的程序描述,能夠支持底層的程序代碼優(yōu)化" title="代碼優(yōu)化">代碼優(yōu)化。然而,目前的Java字節(jié)碼程序都是通過(guò)Java編譯系統(tǒng)" title="編譯系統(tǒng)">編譯系統(tǒng)生成的,人們?nèi)鄙僖环N直接利用Java字節(jié)碼進(jìn)行程序設(shè)計(jì)" title="程序設(shè)計(jì)">程序設(shè)計(jì)的工具。為此,本文提出一種Java字節(jié)碼編程語(yǔ)言" title="編程語(yǔ)言">編程語(yǔ)言,通過(guò)提供一個(gè)Java字節(jié)碼生成系統(tǒng),直接支持Java字節(jié)碼程序設(shè)計(jì)。系統(tǒng)實(shí)現(xiàn)中,選用了Apache組織中的開(kāi)放源碼項(xiàng)目BCEL(Byte Code Engineering Library,字節(jié)碼工程庫(kù))作為Java字節(jié)碼生成工具。
2.?Java字節(jié)碼編程語(yǔ)言設(shè)計(jì)
??? Java字節(jié)碼編程語(yǔ)言的提出,是為了產(chǎn)生優(yōu)化的字節(jié)碼程序,可用于對(duì)Java源程序的編譯系統(tǒng),以及各種程序變換和程序優(yōu)化系統(tǒng)。字節(jié)碼的表達(dá)和優(yōu)化能力都優(yōu)于Java程序,一些Java語(yǔ)言中無(wú)法實(shí)現(xiàn)的功能,利用字節(jié)碼可進(jìn)行描述,例如字節(jié)碼中可使用goto跳轉(zhuǎn)命令,而Java語(yǔ)言沒(méi)有這個(gè)功能。
??? Java字節(jié)碼編程語(yǔ)言文法的設(shè)計(jì),兼顧了Java語(yǔ)言規(guī)范文法與Java虛擬機(jī)的指令格式,采用二者相結(jié)合的形式。Java字節(jié)碼編程語(yǔ)言的程序結(jié)構(gòu)由一個(gè)或多個(gè)類(lèi)組成,每個(gè)類(lèi)中有一個(gè)或多個(gè)域,域分為變量域和方法域,方法中包含了具體的指令語(yǔ)句,指令語(yǔ)句根據(jù)虛擬機(jī)指令設(shè)計(jì)。下面具體列出部分文法。
??? 類(lèi)定義文法沿用Java語(yǔ)言規(guī)范:
表1 類(lèi)定義文法
Modifierà???? public | protected | private | static | abstract | final | native | synchronized | ? ??????????????????????????? transient | volatile | strictfp ? ModifiersOptà????? { Modifier }? ClassDeclarationàclass Identifier [extends Type] [implements TypeList] ClassBody? InterfaceDeclarationà interface Identifier [extends TypeList] InterfaceBody? ClassOrInterfaceDeclarationà ModifiersOpt (ClassDeclaration | InterfaceDeclaration)? ? ClassBodyà{{ClassBodyDeclaration}}? ClassBodyDeclarationà ; | [static] Block?? | ModifiersOpt? MemberDecl? ? MemberDeclà?????? MethodOrFieldDecl?????? | void Identifier VoidMethodDeclaratorRest? |? Identifier ConstructorDeclaratorRest??? |ClassOrInterfaceDeclaration|? |
?
??? 方法體(MethodBody)設(shè)計(jì)為由塊(Block)組成,塊由多個(gè)塊語(yǔ)句(BlockStatements)組成,塊語(yǔ)句又分為局部變量聲明語(yǔ)句(LocalVariableDeclarationStatement)、類(lèi)或接口定義語(yǔ)句(ClassOrInterfaceDeclaration)和指令語(yǔ)句(Instruction)。
??? 指令的設(shè)計(jì)則參考了Java虛擬機(jī)的指令格式,提供了虛擬機(jī)指令的所有功能,按功能可分為以下七類(lèi)語(yǔ)句:
- 裝載和存儲(chǔ)語(yǔ)句(Load_Store)
- 運(yùn)算語(yǔ)句(Arithmetic)
- 類(lèi)型轉(zhuǎn)換語(yǔ)句(Type_ Conversion)
- 對(duì)象創(chuàng)建和操縱語(yǔ)句(Object_Create_Manipulation)
- 操作數(shù)棧管理語(yǔ)句(Operand_Stack_Management)
- 控制轉(zhuǎn)移語(yǔ)句(Control_Transfer)
- 方法調(diào)用" title="方法調(diào)用">方法調(diào)用和返回語(yǔ)句(Method_Invoke_Return)。
??? 相應(yīng)文法如下表:
????????????????????????????????????? 表2 方法及指令定義文法
MethodBodyà Block? Blockà { BlockStatements }? BlockStatementsà {BlockStatement} BlockStatementà?? LocalVariableDeclarationStatement????? |? ClassOrInterfaceDeclaration?????????????? |? [Identifier:] Instruction;? Instructionà? BlockStatement?????????????????????????? | Load_Store?????????????????????????????? |? ???????????????????? Arithmetic????????????????????????????????? | Type_ Conversion????????????????????? |? Object_Create_Manipulation ????? | Operand_Stack_Management???? |? Control_Transfer???????????????????????? | Method_Invoke_Return? |
?
指令語(yǔ)句中方法調(diào)用和返回語(yǔ)句的文法如表3:
????????????????????????????????? 表3 方法調(diào)用和返回語(yǔ)句文法
MethodNameà Identifier? RetTypeà Type? ArgTypeà {[TypeList]}? MethodInvokeKeyword à ?? invokevirtual????????????? | invokeinterface? |? invokespecial????????????? | invokestatic ? Method_Invoke_Returnà MethodInvokeKeyword (ClassName, MethodName, RetType, ArgType) |? ?ireturn | lreturn | freturn | dreturn | areturn | return? |
??? 上表中,方法調(diào)用分為以下四種類(lèi)型:
- 調(diào)用對(duì)象的示例方法,調(diào)度對(duì)象的(虛)類(lèi)型:invokevirtual
- 調(diào)用由接口實(shí)現(xiàn)的方法:invokeinterface
- 調(diào)用需要特殊處理的實(shí)例方法,即實(shí)例初始化方法
、private方法或超類(lèi)方法:invokespecial - 調(diào)用命名的類(lèi)中的類(lèi)(static)方法:invokestatic
3? Java字節(jié)碼生成系統(tǒng)功能及結(jié)構(gòu)?
??? Java字節(jié)碼生成系統(tǒng)的輸入為Java字節(jié)碼編程語(yǔ)言,輸出為Java字節(jié)碼文件。字節(jié)碼生成系統(tǒng)的功能是讀入Java字節(jié)碼編程語(yǔ)言程序,通過(guò)BCEL(字節(jié)碼工程庫(kù))生成字節(jié)碼文件。
??? BCEL字節(jié)碼工程庫(kù)是一個(gè)工具包,用于對(duì)Java類(lèi)文件的靜態(tài)分析,動(dòng)態(tài)創(chuàng)建或修改。開(kāi)發(fā)人員能夠使用BCEL 庫(kù)在一個(gè)較高的抽象層次上實(shí)現(xiàn)所需的功能,而不用具體處理Java字節(jié)碼文件的內(nèi)部細(xì)節(jié)。BCEL完全用Java語(yǔ)言寫(xiě)成,并遵守LGPL條款。
由于BCEL庫(kù)是針對(duì)Java的class文件格式和虛擬機(jī)指令集所設(shè)計(jì)的,直接應(yīng)用BCEL庫(kù)進(jìn)行Java字節(jié)碼文件的生成比較困難,需要了解較多的Java虛擬機(jī)方面的知識(shí)。本文提出的Java字節(jié)碼編程語(yǔ)言的文法與BCEL庫(kù)的字節(jié)碼生成接口相對(duì)應(yīng),易于應(yīng)用BCEL庫(kù)進(jìn)行編譯,完成字節(jié)碼生成。Java字節(jié)碼編程語(yǔ)言成為一座連接Java源程序和字節(jié)碼文件的橋梁,先將Java源程序編譯為中間代碼,再使用BCEL庫(kù)將中間代碼編譯為Java字節(jié)碼,生成class文件。
??? Java字節(jié)碼生成系統(tǒng)可分為詞法分析、語(yǔ)法分析和字節(jié)碼生成三個(gè)階段,其用例圖如下:
???????????????????? 圖1 Java字節(jié)碼生成系統(tǒng)的用例圖
??? 系統(tǒng)的數(shù)據(jù)流圖可表示為:
???? Java字節(jié)碼生成系統(tǒng)中,字節(jié)碼編程語(yǔ)言與BCEL庫(kù)中字節(jié)碼生成接口具有對(duì)應(yīng)關(guān)系,以方法調(diào)用為例,如下表:
表4 java字節(jié)碼編程語(yǔ)言與BCEL庫(kù)生成接口對(duì)應(yīng)關(guān)系
Java字節(jié)碼編程語(yǔ)言方法調(diào)用文法 |
BCEL庫(kù)生成接口 |
MethodNameà Identifier? ? RetTypeà Type? ? ArgTypeà {[TypeList]}? ? MethodInvokeKeyword à ?? ? invokevirtual?????????? | invokeinterface? |? invokespecial?????????? | invokestatic ? ? Method_Invoke_Returnà ? MethodInvokeKeyword(ClassName, MethodName, RetType, ArgType)???? |? ireturn | lreturn | freturn | dreturn ?? | areturn | return? ? |
BCEL庫(kù)中類(lèi)InstructionFactory的方法:? public InvokeInstruction createInvoke (String class_name, String name, Type ret_type,Type[] arg_types, short kind) //kind對(duì)應(yīng)invokevirtual , invokeinterface?????? , invokespecial , invokestatic public static ReturnInstruction createReturn(Type type) //type類(lèi)型對(duì)應(yīng)關(guān)系: T_ARRAY,T_OBJECTà areturn; T_INT,T_SHORT,T_BOOLEAN, T_CHAR,T_BYTEà ireturn; T_FLOATà freturn; T_DOUBLEà dreturn; T_LONGà lreturn; T_VOIDà return; |
4?Java字節(jié)碼生成示例?
??? 下面通過(guò)生成階乘Java程序字節(jié)碼的介紹,說(shuō)明Java字節(jié)碼生成系統(tǒng)功能。左邊是求階乘的Java源程序,右邊是相應(yīng)的字節(jié)碼編程語(yǔ)言代碼。
??? 階乘Java源程序 其中calculateFactorial方法的字節(jié)碼編程語(yǔ)言代碼??
?????????????????????????? 表5 階乘程序和相應(yīng)字節(jié)碼編程語(yǔ)言代碼
階乘Java源程序? |
其中calculateFactorial方法的字節(jié)碼編程語(yǔ)言代碼? |
public class Factorial? {? public int calculateFactorial(int x)? {? ?????? if (x<0)? ?????? ? throw? new ? IllegalArgumentException? ('x must be >=0');? int ret=1;? for(int i=1;i<=x;i++)? ?????? ? ret=ret*i;? ?????? return ret;? }? public static void main? (String[] args)? ? {? ?????? Factorial f=new Factorial();? int n=6;? ?????? System.out.println(? f.calculateFactorial(n) );? ? }? }? |
public class Factorial? {? public int calculateFactorial(int x)? ? {? ? iload? x;? ??? ifge “if1”;? ??? new “java.lang.IllegalArgumentException”;? ??? dup;? ??? ldc “x must be >=0”;? ??? invokespecial ('java.lang.IllegalArgumentException' ,? ' void, ? {'java.lang.String'});? ??? athrow;? if1:? int ret;? push 1;? ??? istore ret;? ??? int i;? ??? push 1;? ??? istore i;? for_begin:??? iload? i;? ??? iload? x;? ??? if_icmpgt “if2”;? ??? iload? ret;? ??? iload? i;? ??? imul;? ??? istore? ret;? ??? iinc? i? 1;? ??? goto “for_begin”;? if2:??? iload? ret;? ??? ireturn;? }? }? |
??? 字節(jié)碼編程語(yǔ)言代碼編譯為BCEL庫(kù)調(diào)用,以階乘為例,以階乘為例,分別討論:
- 類(lèi)和方法聲明:?
????????????????????????????????? ? 表6 類(lèi)和方法聲明轉(zhuǎn)換
字節(jié)碼編程語(yǔ)言代碼? |
BCEL庫(kù)生成代碼? |
public class Factorial { public int ?calculateFactorial(int x) ? {? …… ? } }? |
ClassGen cg = new ClassGen( "Factorial", "java.lang.Object", "Factorial", ACC_PUBLIC| ACC_SUPER, null ); ConstantPoolGen cp = cg.getConstantPool(); InstructionList il = new InstructionList(); MethodGen mg = new MethodGen( ACC_PUBLIC, Type.INT , new Type[]{Type.INT}, ??????????????????????????? new String[]{"x"} ,?????? "calculateFactorial", ??????????????????????????? "Factorial", il, cp );? |
?
- 方法調(diào)用:?
?????????????????????????????????? 表7 方法調(diào)用轉(zhuǎn)換
字節(jié)碼編程語(yǔ)言代碼? |
BCEL庫(kù)生成代碼? |
invokespecial (? "java.lang.IllegalArgumentException" , " void, {"java.lang.String"}); |
il.append( factory.createInvoke( "java.lang.IllegalArgumentException", ? " ? Type.VOID, ? new Type[] {new ObjectType("java.lang.String")}, ? INVOKESPECIAL ) );? |
?
結(jié)束語(yǔ)?
使用Java字節(jié)碼編程語(yǔ)言來(lái)完成字節(jié)碼的生成,屏蔽了底層生成字節(jié)碼的具體方法,通過(guò)生成相應(yīng)虛擬機(jī)命令的擴(kuò)展形式,降低了字節(jié)碼生成的難度。
Java字節(jié)碼編程語(yǔ)言的應(yīng)用廣泛,可用于Java代碼優(yōu)化,如對(duì)Java源程序進(jìn)行部分求值優(yōu)化后,可對(duì)生成的滯留程序和例化程序編譯為中間語(yǔ)言的形式,在利用BCEL庫(kù)生成字節(jié)碼,完成進(jìn)一步的字節(jié)碼優(yōu)化。還可以對(duì)Java字節(jié)碼編程語(yǔ)言進(jìn)行優(yōu)化,去掉冗余的控制轉(zhuǎn)移和方法調(diào)用,進(jìn)而生成更緊湊的Java字節(jié)碼。
參考文獻(xiàn)?
[1] James Gosling,Bill Joy,Guy Steele,Gilad Bracha 《The Java Language Specification》 ADDISON-WESLEY? 2000
[2] Markus Dahm《Byte Code Engineering With the BCEL API》
Freie Universit?t Berlin Institut für Informatik, Technical Report B-17-98? http://inf.fuberlin.de/pub/BCEL/report.ps
[3] 玄偉劍等譯.《Java 虛擬機(jī)規(guī)范》.北京大學(xué)出版社,1997