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