1. 引言
??? 眾所周知,Java語言依靠Java虛擬機(jī)對字節(jié)碼程序的支持,實(shí)現(xiàn)了跨平臺(tái)特征。作為一種中間語言,Java字節(jié)碼提供了匯編指令級(jí)的程序描述,能夠支持底層的程序代碼優(yōu)化" title="代碼優(yōu)化">代碼優(yōu)化。然而,目前的Java字節(jié)碼程序都是通過Java編譯系統(tǒng)" title="編譯系統(tǒng)">編譯系統(tǒng)生成的,人們?nèi)鄙僖环N直接利用Java字節(jié)碼進(jìn)行程序設(shè)計(jì)" title="程序設(shè)計(jì)">程序設(shè)計(jì)的工具。為此,本文提出一種Java字節(jié)碼編程語言" title="編程語言">編程語言,通過提供一個(gè)Java字節(jié)碼生成系統(tǒng),直接支持Java字節(jié)碼程序設(shè)計(jì)。系統(tǒng)實(shí)現(xiàn)中,選用了Apache組織中的開放源碼項(xiàng)目BCEL(Byte Code Engineering Library,字節(jié)碼工程庫)作為Java字節(jié)碼生成工具。
2.?Java字節(jié)碼編程語言設(shè)計(jì)
??? Java字節(jié)碼編程語言的提出,是為了產(chǎn)生優(yōu)化的字節(jié)碼程序,可用于對Java源程序的編譯系統(tǒng),以及各種程序變換和程序優(yōu)化系統(tǒng)。字節(jié)碼的表達(dá)和優(yōu)化能力都優(yōu)于Java程序,一些Java語言中無法實(shí)現(xiàn)的功能,利用字節(jié)碼可進(jìn)行描述,例如字節(jié)碼中可使用goto跳轉(zhuǎn)命令,而Java語言沒有這個(gè)功能。
??? Java字節(jié)碼編程語言文法的設(shè)計(jì),兼顧了Java語言規(guī)范文法與Java虛擬機(jī)的指令格式,采用二者相結(jié)合的形式。Java字節(jié)碼編程語言的程序結(jié)構(gòu)由一個(gè)或多個(gè)類組成,每個(gè)類中有一個(gè)或多個(gè)域,域分為變量域和方法域,方法中包含了具體的指令語句,指令語句根據(jù)虛擬機(jī)指令設(shè)計(jì)。下面具體列出部分文法。
??? 類定義文法沿用Java語言規(guī)范:
表1 類定義文法
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è)塊語句(BlockStatements)組成,塊語句又分為局部變量聲明語句(LocalVariableDeclarationStatement)、類或接口定義語句(ClassOrInterfaceDeclaration)和指令語句(Instruction)。
??? 指令的設(shè)計(jì)則參考了Java虛擬機(jī)的指令格式,提供了虛擬機(jī)指令的所有功能,按功能可分為以下七類語句:
- 裝載和存儲(chǔ)語句(Load_Store)
- 運(yùn)算語句(Arithmetic)
- 類型轉(zhuǎn)換語句(Type_ Conversion)
- 對象創(chuàng)建和操縱語句(Object_Create_Manipulation)
- 操作數(shù)棧管理語句(Operand_Stack_Management)
- 控制轉(zhuǎn)移語句(Control_Transfer)
- 方法調(diào)用" title="方法調(diào)用">方法調(diào)用和返回語句(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? |
?
指令語句中方法調(diào)用和返回語句的文法如表3:
????????????????????????????????? 表3 方法調(diào)用和返回語句文法
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)用分為以下四種類型:
- 調(diào)用對象的示例方法,調(diào)度對象的(虛)類型:invokevirtual
- 調(diào)用由接口實(shí)現(xiàn)的方法:invokeinterface
- 調(diào)用需要特殊處理的實(shí)例方法,即實(shí)例初始化方法
、private方法或超類方法:invokespecial - 調(diào)用命名的類中的類(static)方法:invokestatic
3? Java字節(jié)碼生成系統(tǒng)功能及結(jié)構(gòu)?
??? Java字節(jié)碼生成系統(tǒng)的輸入為Java字節(jié)碼編程語言,輸出為Java字節(jié)碼文件。字節(jié)碼生成系統(tǒng)的功能是讀入Java字節(jié)碼編程語言程序,通過BCEL(字節(jié)碼工程庫)生成字節(jié)碼文件。
??? BCEL字節(jié)碼工程庫是一個(gè)工具包,用于對Java類文件的靜態(tài)分析,動(dòng)態(tài)創(chuàng)建或修改。開發(fā)人員能夠使用BCEL 庫在一個(gè)較高的抽象層次上實(shí)現(xiàn)所需的功能,而不用具體處理Java字節(jié)碼文件的內(nèi)部細(xì)節(jié)。BCEL完全用Java語言寫成,并遵守LGPL條款。
由于BCEL庫是針對Java的class文件格式和虛擬機(jī)指令集所設(shè)計(jì)的,直接應(yīng)用BCEL庫進(jìn)行Java字節(jié)碼文件的生成比較困難,需要了解較多的Java虛擬機(jī)方面的知識(shí)。本文提出的Java字節(jié)碼編程語言的文法與BCEL庫的字節(jié)碼生成接口相對應(yīng),易于應(yīng)用BCEL庫進(jìn)行編譯,完成字節(jié)碼生成。Java字節(jié)碼編程語言成為一座連接Java源程序和字節(jié)碼文件的橋梁,先將Java源程序編譯為中間代碼,再使用BCEL庫將中間代碼編譯為Java字節(jié)碼,生成class文件。
??? Java字節(jié)碼生成系統(tǒng)可分為詞法分析、語法分析和字節(jié)碼生成三個(gè)階段,其用例圖如下:
???????????????????? 圖1 Java字節(jié)碼生成系統(tǒng)的用例圖
??? 系統(tǒng)的數(shù)據(jù)流圖可表示為:
???? Java字節(jié)碼生成系統(tǒng)中,字節(jié)碼編程語言與BCEL庫中字節(jié)碼生成接口具有對應(yīng)關(guān)系,以方法調(diào)用為例,如下表:
表4 java字節(jié)碼編程語言與BCEL庫生成接口對應(yīng)關(guān)系
Java字節(jié)碼編程語言方法調(diào)用文法 |
BCEL庫生成接口 |
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庫中類InstructionFactory的方法:? public InvokeInstruction createInvoke (String class_name, String name, Type ret_type,Type[] arg_types, short kind) //kind對應(yīng)invokevirtual , invokeinterface?????? , invokespecial , invokestatic public static ReturnInstruction createReturn(Type type) //type類型對應(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é)碼生成示例?
??? 下面通過生成階乘Java程序字節(jié)碼的介紹,說明Java字節(jié)碼生成系統(tǒng)功能。左邊是求階乘的Java源程序,右邊是相應(yīng)的字節(jié)碼編程語言代碼。
??? 階乘Java源程序 其中calculateFactorial方法的字節(jié)碼編程語言代碼??
?????????????????????????? 表5 階乘程序和相應(yīng)字節(jié)碼編程語言代碼
階乘Java源程序? |
其中calculateFactorial方法的字節(jié)碼編程語言代碼? |
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é)碼編程語言代碼編譯為BCEL庫調(diào)用,以階乘為例,以階乘為例,分別討論:
- 類和方法聲明:?
????????????????????????????????? ? 表6 類和方法聲明轉(zhuǎn)換
字節(jié)碼編程語言代碼? |
BCEL庫生成代碼? |
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é)碼編程語言代碼? |
BCEL庫生成代碼? |
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é)束語?
使用Java字節(jié)碼編程語言來完成字節(jié)碼的生成,屏蔽了底層生成字節(jié)碼的具體方法,通過生成相應(yīng)虛擬機(jī)命令的擴(kuò)展形式,降低了字節(jié)碼生成的難度。
Java字節(jié)碼編程語言的應(yīng)用廣泛,可用于Java代碼優(yōu)化,如對Java源程序進(jìn)行部分求值優(yōu)化后,可對生成的滯留程序和例化程序編譯為中間語言的形式,在利用BCEL庫生成字節(jié)碼,完成進(jìn)一步的字節(jié)碼優(yōu)化。還可以對Java字節(jié)碼編程語言進(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