您的位置:首页 > 编程语言 > Java开发

一种动静态结合的Java程序异常处理优化方法

2016-05-07 13:32 615 查看
摘要

本发明属于Java编译运行环境设计技术领域,具体一种Java动静态结合的异常处理优化方法。本发明把动静结合的编译运行环境分为两个阶段:静态处理阶段和动态执行阶段。静态处理阶段主要是在静态编译器里分析和收集程序的异常处理信息,如产生异常的语句,异常的类型及异常着陆点等信息;动态执行阶段主要是利用静态分析得到的异常处理信息,在异常发生的时候根据异常的类型和异常着陆点跳转到相应的异常处理代码段,执行异常处理的相关操作。本发明糅合动、静优化技术来完成Java程序编译工作,从而达到提供一个最优的异常处理机制的效果。

权利要求

1.一种Java动静态结合的异常处理优化方法,其特征在于把动静结合的编译运行环境分为两个阶段:静态处理阶段和动态执行阶段,具体步骤如下: (1)在静态处理阶段,分析识别Java程序中所有可能抛出异常的语句; (2)在静态处理阶段,利用静态编译器前端分析try-catch-finalIy的层次关系; (3)在静态处理阶段,确定可能抛出异常的语句的异常着陆点; (4)在静态处理阶段,将静态编译器收集到的异常处理信息转化为动态编译器需要的异常处理信息;
(5)在动态执行阶段,利用动态编译器提供的运行时支持函数来完成异常处理的操作; 其中, 所述分析识别Java程序中可能抛出异常的语句的步骤为: 首先,获得Java源程序转化的抽象语法树后。遍历整个抽象语法树,查找可能引发不受检查异常的语句,记录它的位置; 接着,对记录下来的每一个节点查看其父节点是否是if语句;如果不是,则对其进行标记,如果是,则检查判断条件是否包含当前节点发生异常的条件,如果没有,同样对该节点做标记; 然后,对标记下来的每个节点,根据其类型判断其引发异常的条件,然后在抽象语法树的适当位置插入相应的补偿代码;
所述分析try-catch-finalIy的层次关系的具体步骤为: 当遇到一个try块时,首先将当前的抽象语法树的遍历结果的状态记录下来,然后将当前的try块的信息记录到一个vector上;接着,判断刚才记下来的抽象语法树的状态,如果在这次try之前没有遇到过try块或catch块或finally块,则将当前try块的parent_try记为空;如果上一层是try块,则上一层的try块则是当前try块的parent_try ;如果是catch块或finally块,那么当前的try块的parent_try则是该catch块或finally块对应的try块;
所述确定可能抛出异常的语句的异常着陆点的步骤完成两个方面工作: (I)确定程序的异常着陆点 由步骤一和步骤二中收集到的可能抛出异常的语句集合和当前遍历到的try块的状态的栈的信息作为输入参数,得到集合中所有可能抛出异常的语句的异常着陆点;其方法是把需要处理的可能抛出异常的语句按照所处区域位置的不同分为四类,并且分别进行处理: O需要处理的可能抛出异常的语句处于try块中,这时的异常着陆点是相继的catch块、finally块,或者是parent_try相继的catch块、finally块,所需要做的只是把相应try块的EH_block_label作为异常着陆点;这里所述的try块的EH_block_label是指该try块对应的异常处理代码段的开始,该label下记录着进行对异常类型的分析和跳转;
2)需要处理的可能抛出异常的语句处于catch块中,这种情况的异常着陆点有两种可能:一种是如果本catch块存在相继的finally块,着陆点就是相继的finally块;另一种情况是不存在相继的finally块,那么就判断是否存在parent_try,并把着陆点定为parent_try 相继的 EH_block_label ;3)需要处理的可能抛出异常的语句处于final块中,这种情况下,直接判断是否存在parent_try,并把着陆点定为 parent_try 相继的 EH_block_label ;4)需要处理的可能抛出异常的语句处于普通区域,即不属于上述三种情况,或上述三种情况中没有找到异常着陆点,这种情况下,一旦异常发生,没有处理代码存在;(2)构造异常代码在分析出异常着陆点之后,编译器就构造异常处理代码,其算法以try-catch-finally的粒度来完成;其步骤为:第一,生成一个EH_block_label标签,并在生成好的try块中的代码之后加入至EH_block_label标签的跳转;第二,在EH_bloCk_label标签之后生成异常类型的判断以及跳转的代码,即判断何种类型的异常由哪个catch来处理;如果有finally块存在,则在判断完之后加入finally代码;第三,逐个生成catch_block_label标签和相应的catch块代码,并在每个catch块代码的最后加入到下一个catch_block_label标签的跳转;第四,生成finally_block_label标签和相应的finally块代码;所述异常处理信息的转化的过程作为静态编译器的IR向动态编译器的IR的转化的过程处理;所述利用运行时环境的支持函数完成异常处理,主要是在即时编译器里面的异常处理的实现方式,包括栈展开、栈回溯;其中,在进行栈展开操作时,运行时环境的支持函数根据异常产生函数的方法栈得到当前函数的异常处理信息,如果该函数的异常处理代码可以处理该异常,则将程序跳转到异常处理代码开始处执行;如果当前函数的异常处理代码不能处理该异常,运行时环境的支持函数根据当前方法的方法栈的信息得到上一层调用者的方法栈的基址指针retbp,同时还得到上一层方法的返回地·址retpc,这样根据上一层调用函数的方法栈信息得到上一层函数的异常处理信息;如果该函数的异常处理代码可以处理该异常,程序同样跳转到该异常处理代码的开始,否则,再通过上述方法得到上层调用者的异常处理信息,直到找到可以处理该异常的异常处理代码为止;如果所有函数的异常处理代码都不能处理该异常,则程序终止运行。

说明

一种动静态结合的Java程序异常处理优化方法

技术领域

[0001] 本发明属于Java编译运行环境设计技术领域,具体涉及Java静态编译器和动态虚拟机中的异常处理优化方法。

背景技术

[0002] 异常处理机制是现代编程语言中普遍采用的一种提高程序可靠性的方法。作为目前应用最广泛的面向对象编程语言,Java也将异常处理机制视为语言规范的一个重要方面。如何正确地实现Java的异常处理机制是实现任何Java编译运行环境的关键部分。

[0003]目前Java编译运行环境主要采用静态和动态两种编译优化方式。静态优化方式是将Java源程序或字节码(byte code)直接编译成可执行代码;动态编译优化方式,则先将Java源程序翻译成平台无关的字节码,然后由Java虚拟机(Java Virtual Machine)对字节码进行解释或优化编译执行。

[0004] 上述传统Java编译运行环境存在着各自的缺陷:静态编译优化将程序编译成可执行代码,它破坏了 Java的跨平台性,其优化的效果也不理想。而动态编译优化则会带来高昂的运行时开销,给通过动态编译执行的程序带来了额外的负担。而糅合动、静优化技术来优化Java程序的系统框架在静态端对源程序进行静态分析与优化并将静态分析的结果传递给动态端,动态端结合静态分析的结果进行基于采样的动态优化,这样既保留Java的跨平台性,又能减少运行时开销,保障程序性能。

[0005] 然而,现有的Java异常处理机制一般只适用于纯静态或纯动态的Java编译运行环境。所以要完成以上工作还存在的一个问题是:目前的技术中缺少一套既适用于静态优化,又能在Java虚拟机中正常工作的Java异常处理机制。

发明内容

[0006] 本发明的目的在于针对目前的技术中缺少一套既适用于静态优化,又能在Java虚拟机中正常工作的Java异常处理机制的这一问题,提出一种Java动静态结合的异常处理优化方法。

[0007] 本发明调研了不同的Java静态编译器和动态虚拟机中对异常处理机制设计的差异,发现这些设计在处理原理上具有很大程度的相似,只是在具体的算法实现时有较大的差异。该结果说明,建立统一优化方法框架的可能性和优越性。

[0008] 本发明采用的技术方案为:为实现一个糅合动、静优化技术来完成Java程序编译工作的框架,在这个框架上再完成适用的各种动、静态优化方法,从而达到提供一个最优的异常处理机制的效果。

[0009] 本发明调研了动静结合的编译运行环境的特点:异常信息的收集和异常处理是分别在两个不同的环境的。一般来说,异常信息的收集这一过程发生在静态编译器端,而真正执行异常处理的过程发生在动态虚拟机里面,即是动静结合的编译运行环境区别于传统的纯静态或纯动态的编译运行环境的最关键之处。[0010] 针对调研中动静结合的编译运行环境的特点,本发明把动静结合的编译运行环境分为两个阶段:静态处理阶段和动态执行阶段。静态处理阶段主要是在静态编译器里分析和收集程序的异常处理信息,如产生异常的语句,异常的类型及异常着陆点等信息;动态执行阶段主要是利用静态分析得到的异常处理信息,在异常发生的时候根据异常的类型和异常着陆点跳转到相应的异常处理代码段,执行异常处理的相关操作。

[0011] 本发明对基于动静结合的编译运行环境的Java异常处理方法,共分为5个阶段,图1中是异常处理编译、执行设计的整体示意图,具体步骤如下:

[0012] 1、在静态处理阶段,分析识别Java程序中所有可能抛出异常的语句;

[0013] 2、在静态处理阶段,利用静态编译器前端分析try-catch-finalIy的层次关系;

[0014] 3、在静态处理阶段,确定可能抛出异常的语句的异常着陆点;

[0015] 4、在静态处理阶段,将静态编译器收集到的异常处理信息转化为动态编译器需要的异常处理信息;

[0016] 5、在动态执行阶段,利用动态编译器提供的运行时支持函数来完成异常处理的跳转等操作。

[0017] 前三个阶段只要是分析并收集程序的异常信息,这些异常处理信息主要用于静态编译器对程序进行优化的过程。由于静态编译器里收集到的异常处理信息并不能直接在动态虚拟机上使用,因此,该异常处理机制会在适当的时机将静态收集到的异常处理信息转化为动态虚拟机需要的异常处理信息,这一过程对应于阶段四。最后,在Java程序运行过程中,如果有异常产生,该机制会利用运行时环境提供的支持函数,再结合异常处理信息来跳转到相应的异常处理的代码。

[0018] 本发明的有益效果是:1)本发明提供了一个实现糅合动、静优化技术来完成Java程序编译工作的统一优化框架,实现了 Java程序在动静结合的环境中编译和运行。2)本发明使得一个Java程序可以同时运用动静态异常处理优化,提供了更多的优化机会。3 )本发明使得更多不同的优化算法能在这一框架下方便的被实现,很大程度上方便了今后异常处理优化的设计和实现。4)框架的实现不针对具体的某一平台,这样的设计增加了本框架的平台可移植性。

附图说明

[0019] 图1所示为动静结合的Java异常处理机制的整体框架。

[0020] 图2所示为实施例Java异常代码片段。

[0021] 图3所示为实施例代码片段的补偿代码。

[0022] 图4所示为实施例对应的异常处理代码示意图。

[0023] 图5所示为实施例动态编译器的表示形式。

[0024] 图6所示为程序栈空间中方法栈的示意图。

具体实施方式

[0025] 本发明设计并实现了上述的动静结合Java异常处理机制的整体框架,本节对该框架的具体实施作一个详细的介绍。图1为动静结合的Java异常处理机制的整体框架,描述了本发明框架中,Java程序编译和执行的流程。本发明分5个步骤:前4个步骤属于静态分析的范畴,最后一个步骤是动态执行的范畴。

[0026] 下面将以实施例的形式对本发明每个步骤进行详细的介绍,展示本框架把Java代码编译成可执行代码的全过程。(实施例Java异常代码片段见图2)。

[0027] 步骤一、分析识别可能抛出异常的语句

[0028] 本步骤目的在于得到能够引发异常的语句,通常是下面三种语句中的一种:(I)throw语句;(2)可能引发异常的函数调用语句;(3)在程序运行过程中可能违反Java语言的语义规则的语句。以图2中的代码片段为例,第5行的除法操作就是一个能够引发异常的语句,如果right这个变量的值为0,程序就会产生一个除零异常。

[0029] 静态编译器总会有一个将Java源程序转化为抽象语法树的过程。本发明的框架在Java程序转化为相应的抽象语法树之后,对该抽象语法树进行操作,识别那些可能引发不受检查异常的节点。下面我们给出处理的流程。

[0030] 首先,获得Java源程序转化后的抽象语法树后,遍历整个抽象语法树,查找可能弓I发不受检查异常的语句,记录它的位置。

[0031] 接着,对记录下来的每一个节点查看其父节点是否是if语句。如果不是,则对其进行标记。如果是,则检查判断条件是否包含当前节点发生异常的条件,如果没有,同样对该节点做标记。

[0032] 然后对标记下来的每个节点,根据其类型判断其引发异常的条件,然后在抽象语法树的适当位置插入相应的补偿代码。以图2中的代码为例,静态编译器会对本程序添加判断,判断变量right的值是否为0,如不是则正常运行;如是则抛出异常。补偿后的代码如图3,补偿代码中插入了第5、第6行的判断。

[0033] 经过上述的处理后,程序中可能引发异常的点就由throw语句的集合和会引发异常的函数调用语句的集合组成,即补偿代码(图3)中的第6行throw语句。而函数调用语句可以分为用户自定义函数调用语句和库函数调用语句。用户自定义函数抛出异常的本质还是由函数体内的throw语句和函数调用语句抛出的,因此被调用的用户自定义函数抛出的异常又可以归结为函数体内的throw语句和函数调用语句抛出的。

[0034] 步骤二、分析try-catch-finally的层次关系

[0035] try-catch-finally的层次关系也是处理异常的重要信息,收集这部分的信息必不可少。该步骤和步骤一不存在因果关系,可以交换顺序,在本发明实现中为了方便将本步骤放在步骤一之后。

[0036] 本步骤的难点在于try-catch-finally块是可以嵌套的,在try块和catch块甚至是finally块中都可以包含另外的try-catch-finally块,实施例代码(图2)就是典型的情况。正确地判断try-catch-finally块的嵌套关系是编译器正确实现异常处理机制的基础。本发明设计的算法能正确地分析程序中try块的层次关系。该算法同样是在Java源程序转化为相应的抽象语法树后进行的,故本步骤分析try块的层次关系同样是基于Java源程序对应的抽象语法树的。本节着重分析的是try块的上一层try块的关系,为了描述的方便称为parent_try关系,下同。

[0037] 下面是算法的描述:当遇到一个try块时,首先将当前的抽象语法树的遍历结果的状态记录下来,然后将当前的try块的信息记录到一个vector上。接着,判断刚才记下来的抽象语法树的状态,如果在这次try之前没有遇到过try块或catch块或finally块,则将当前try块的parent_try记为空。如果上一层是try块,则上一层的try块则是当前try块的parent_try ;如果是catch块或finally块,那么当前的try块的parent_try则是该catch块或finally块对应的try块。

[0038] 用该算法可以很方便地得出图2中第I行的try的parent_try是空,而第2行的try的parent_try是第I行的try,这样就得到了第2行的try是一个nested try的信息。

[0039] 上述算法的伪代码如下:[0040] 算法 分析try块的parent_try关系[0041] 输入 一个由下列部分组成的try块层次关系的框架:[0042] (I) Java源代码对应的抽象语法树AST。 [0043] (2)— ■"个用于记录try块信息的集合V。[0044] (3)— ■"个用于记录当前遍历到的try块的状态的栈S。[0045] 输出 包含所有try块的parent_try信息的状态的集合。[0046] /*V和S的初始状态都为空。*/ [0047] Begin [0048]
(I)从抽象语法树AST的根节点开始遍历, [0049] (2) if当前节点η代表一个try块[0050] (3) currentTry:= η;[0051] (4) enclosingTry:=栈S的栈顶元素对应的try块;[0052] (5) enclosingType:=栈S的栈顶元素的类型;[0053] (6) add currentTry into V;[0054] (7) ifenclosingTry 为空[0055] (8) currentTry->parent_try 为空[0056] (9)
else[0057] (10) ifenclosingType == tryType[0058] (11) currentTry->parent_try:= enclosingTry;[0059] (12) else ifenclosingType == (catchType finallyType)[0060] (13) currentTry->parent_try:= enclosingTry->parent_try[0061] (14) end if[0062] (15) end if[0063] (16)
push S (Pair (currentTry, tryType));[0064] (17) forcurrentTry 中的每一条语句 smtdo[0065] (18) ifsmt可能引发异常[0066] (19) record—landpad (smt) //确定异常着陆点[0067] (20) end if[0068] (21) end for[0069] (22) 分析`currentTry内部try块的层次关系[0070] (23) pop S;[0071] (24) 为 currentTry
生成一个标签 after—EH—label[0072] (25) ifcurrentTry 后面有 finally 块[0073] (26) push S(Pair(currentTry, finallyType));[0074] (27) 处理该finally块并分析其内部try块的层次关系[0075] (28) pop S;[0076] (29) end if[0077] (30) end if[0078] EncL

[0079] 步骤三、确定可能产生异常的语句的异常着陆点

[0080] 基于上面两个步骤中收集的信息,本步骤完成以下两个方面:1)确定程序的异常着陆点,即构造异常的控制流信息。2)构造异常代码。

[0081] (I)确定程序的异常着陆点

[0082] 在确定程序中所有try块的层次关系之后,编译器就有足够的信息确定程序中可能抛出异常的语句的异常着陆点。寻找异常着陆点的算法需要步骤一和二中收集到的可能抛出异常的语句集合和当前遍历到的try块的状态的栈的信息作为输入参数,从而得到集合中所有可能抛出异常的语句的异常着陆点。为了确定异常着陆点的方便,本发明把需要处理的可能抛出异常的语句按照所处区域位置的不同分为四类,并且分别进行处理。

[0083] I)需要处理的可能抛出异常的语句处于try块中。这是异常发生最自然的情况,这时的异常着陆点应该是相继的catch块、finally块或者parent_try相继的catch块、finally块,所需要做的只是把相应try块的EH_block_label作为异常着陆点。这里出现的try块的EH_block_label是指该try块对应的异常处理代码段的开始,该label下记录着进行对异常类型的分析和跳转,这些都是在构建异常处理代码的时候生成的。

[0084] 2)需要处理的可能抛出异常的语句处于catch块中。这种情况的异常着陆点有两种可能:一种是如果本catch块存在相继的finally块,着陆点就是相继的finally块;另一种情况是不存在相继的finally块,那么就判断是否存在parent_try,并把着陆点定为parent_try 相继的 EH_block_label

[0085] 3)需要处理的可能抛出异常的语句处于final块中。这种情况下,直接判断是否存在parent_try,并把着陆点定为parent_try相继的EH_block_label。

[0086] 4)需要处理的可能抛出异常的语句处于普通区域。即不属于上述三种情况,或上述三种情况中没有找到异常着陆点,这种情况就说明程序的异常没有捕获的对象,一旦异常发生,没有处理代码存在。

[0087] 上述算法的伪代码如下:

[0088] 算法:确定异常着陆点

[0089] 输入:可能抛出异常的语句smt及当前遍历到的try块的状态的栈S

[0090] 输出:可能抛出异常的语句的异常着陆点

[0091] 算法的过程如下:

[0092] Begin record—landpad

[0093] (I)得到当前处理到的语句smt

[0094] (2) currentTry:=栈S的栈顶元素对应的try块;

[0095] (3) currentType:=栈S的栈顶元素的类型;

[0096] (4) ifcurrentType == tryType0097]

0098]

0099]

0100]0101]0102]

0103]

0104]

0105]

0106]

0107]

0108]

smt->landpad:= currentTry->EH_block_labelend if

ifcurrentType == catchType

if currentTry 后面有 finally 块smt->landpad:= finally 块的开始else if currentTry->parent_try 不为空

smt->landpad:= currentTry->parent_try->EH_block_labelend ifend if

ifcurrentType == finallyType

if currentTry->parent_try 不为空

smt->landpad:= currentTry->parent_try->EH_block_label

0109] (17) end if

0110] (18) end if

0111] End。

0112] (2)构造异常代码

0113] 在分析出了异常着陆点之后,编译器就可以构造异常处理代码了。由于在Java的Byte code中只有try、catch和finally块中的代码,却没有他们之间的运行逻辑关系,本发明需要补偿这部分的逻辑,使Java程序可以正确的运行。这个算法在分成Java代码的同时,补偿相应的逻辑跳转语句,使得异常可以正确的被处理。

[0114] 本算法以try-catch-finally的粒度来完成,以一个try-catch-finally块为例。第一,是生成一个EH_block_label标签,并在生成好的try块中的代码之后加入至EH_block_label标签的跳转。第二,在EH_bloCk_label标签之后生成异常类型的判断以及跳转的代码。即判断何种类型的异常由哪个catch来处理。如果有finally块存在,则在判断完之后加入finally代码。第三,逐个生成catch_block_label标签和相应的catch块代码,并在每个catch块代码的最后加入到下一个catch_block_label标签的跳转。第四,生成f
inally_block_label标签和相应的f inally块代码。经过这样四步,就完成一个try-ca块的异常处理代码构建工作。

[0115] 上述算法的伪代码如下:

[0116] 算法:构建异常处理代码

[0117] 输入:一个由下列部分组成的try块层次关系的框架:

[0118] (I) Java源代码对应的抽象语法树AST。

[0119] (2) 一个记录了所有try块信息的集合V。

[0120] (3) 一个用于记录当前处理到的try块的状态的栈S。

[0121] 输出:每个try块对应的异常处理的代码结构。

[0122] 算法的过程如下:

[0123] Begin

[0124] (I) for 集合 V 中的每一个 try 信息 currentTrydo

[0125] (2) 为 currentTry 生成一个 EH—block—label 标签[0126] (3) 生成异常类型的判断以及跳转的代码[0127] (4) if currentTry 后面有 finally 块[0128] (5) push S(Pair(currentTry, finallyType));[0129] (6) 生成finally块里面的代码[0130] (7) pop S;[0131] (8) end if[0132] (9) 生成一个Unwind_Resume的函数调用//该函数是运行时环境提供的[0133]
(10) forcurrentTry 对应的每一个 catch 块 do[0134] (11) 为该catch块生成一个catch_block_label标签[0135] (12) push S (Pair (currentTry, catchType));[0136] (13) 生成catch块里面的代码[0137] (14) pop S;[0138] (15) 生成一条跳转语句到currentTry的after_EH_label标签[0139] (16) end for[0140] (17) if currentTry
后面有 finally 块[0141] (18) 为该 finally 块生成一个 finally_block_label 标签[0142] (19) push S(Pair(currentTry, finallyType));[0143] (20) 生成finally块里面的代码[0144] (21) pop S;[0145] (22) if currentTry->parent_try 不为空[0146] (23) 生成一条跳转语句到 currentTry->parent_try 的 EH_block_label标签
[0147] (24) else[0148] (25) 生成一个Unwind_Resume的函数调用[0149] (26) end if[0150] (27) end if[0151] (28) end for[0152] EncL `[0153] 以图2中的代码为例,在分析获得第2行的try的parent_try是第I行的try之

后,可以将图2中的代码转化为图4所示的代码结构。经过确定异常着陆点的算法分析之后,可以知道try block inside的异常着陆点是Label 2, try block outside的异常着陆点是Label 5, catch block I的异常着陆点是Label 4, catch block 2的异常着陆点是Label 7。这样图2中的代码的所有异常着陆点的信息就收集完毕了,其对应的异常处理代码就如图4所示。

[0154] 步骤四、异常处理信息的转化

[0155] 经过前三个阶段的处理,静态编译器已经获得足够的异常处理信息来对程序进行静态优化了。但由于动静结合的编译运行环境分为静态端和动态端,并且动态端的异常处理机制的实现往往不同于静态端,因此,在从静态端转到动态段之前,我们需要将已有的异常处理信息转化为动态端需要的异常处理信息。[0156] 每个编译器都有一套适合自身特点的中间表示(Intermediate Representation,简称IR),各种优化方法都是针对特定的IR。这些IR上面携带了大量的编译信息,其中就包括异常处理的信息。因此,异常处理信息的转化很大程度上就是静态编译器的IR向动态编译器的IR的转化的过程。

[0157] 例如,在静态编译器里,异常处理信息是由一系列的表组成的,如异常类型信息是在一个异常类型的表里面的,异常着陆点也是在一个指定的表结构里面的。当异常发生时,首先要在异常类型表里面确认异常的类型,然后根据异常的类型到指定的表结构里面查找异常着陆点的信息,最后才能跳转到异常处理代码处执行。而在动态编译器里,程序被表示成一个控制流图的形式,程序的基本信息都反映在该控制流图上的点和边。图5即是图4转化后的形式,其中所有跳转关系都转化为图上的边。

[0158]由于每种IR都有其自身的特点,因此,具体的转化的过程是根据具体的静态编译器和动态编译器的不同而不一样的,这个过程这里就不展开罗列了,本技术领域的一般技术人员都可以处理。

[0159] 另外,在异常处理信息转化的过程中需要注意的以下几个问题:异常处理代码的转化、异常类型的转化、异常处理控制流的转化等。

[0160] 步骤五、利用运行时环境的支持函数完成动态执行

[0161] 在本发明动静结合的编译运行环境中的最后一个步骤,Java程序在动态编译器(一般是Java虚拟机)里面执行。本发明主要关注在即时编译器里面的异常处理的实现方式,如栈展开、栈回溯等。

[0162] 以栈展开为例,在栈展开的异常处理算法里,为了执行异常查询的操作,运行时环境必须可以从函数调用栈栈顶开始,逐个扫描函数的异常处理信息,查找可以处理该异常的异常处理代码。该过程一般是由运行时环境的支持函数来完成的。

[0163] 要实现这样一个栈展开的操作,我们必须了解函数调用栈的一些细节。在程序运行的时候,虚拟机会为该程序创建一个固定的运行空间。对于即时编译,该空间是存放在本地方法栈的。本地方法栈实际上就是传统的C栈。

[0164] 图6给出了程序栈空间中方法栈的示意图,其中方法调用过程是方法I调用方法2,方法2调用方法3。由图6可知,方法栈空间的连接和方法的当前执行点分别由方法栈中的retbp和retpc建立的。在进行栈展开操作时,运行时环境的支持函数会根据异常产生函数的方法栈得到当前函数的异常处理信息,如果该函数的异常处理代码可以处理该异常,则将程序跳转到异常处理代码开始处执行。如果当前函数的异常处理代码不能处理该异常,运行时环境的支持函数会根据当前方法的方法栈的信息得到上一层调用者的方法栈的基址指针retbp,同时还可以得到上一层方法的返回地址retpc,这样根据上一层调用函数的方法栈信息得到上一层函数的异常处理信息。如果该函数的异常处理代码可以处理该异常,程序同样跳转到该异常处理代码的开始,否则的话再通过上述方法得到上层调用者的异常处理信息,直到找到可以处理该异常的异常处理代码为止。如果所有函数的异常处理代码都不能处理该异常,则程序终止运行。









内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: