

英语原文共 9 页,剩余内容已隐藏,支付完成后下载完整资料
使用子程序的代价与效益
Stephen N. Freund!
Department of Computer Science
Stanford University
Stanford, CA 94305-9045
freunds@cs.stanford.edu
摘要:
Java 字节码子程序用于将java源程序中的try-finally 结构编译为简洁的专用指令集。然而,通过子程序所得到的节省空间的好处,相比使用简单的编译策略,却使得java字节码检查器和jvm的其他部份的实现增大了大量的复杂度。这篇论文调查研究在保持子节码程序中保持子程序和去除子程序的权衡。我们比较了如上述所说的字节码检察器的实现代价以及实现了子程序的虚拟机在编译一系列有代表性的java程序所节省的空间。
- 介绍
java是一种静态通用编程语言架构,目的是便于编码后便于在网络中传输。在标准的实现中,一个java 程序是被编译成字节码后由java虚拟机解释执行。我们指这样的字节码语言为JVML。
因为字节码被人为改写或者在网络传输中可能被污染,java虚拟机包含了一个字节码检查器,在字节码解释执行时进行一系列的检查。字节码检查器的正确性对于java虚拟机的安全是极其重要的,而这在别处已有示证[DFW96]。为了一步获得正确的,正式的规范的验证,我们正在开发一个规范的静态字节码形式,可用于大量JVML片段的类型系统。这个系统包含类,接口,方法,构造器,异常,子程序和数组。虽然还不是完全的JVML,但是这个类型系统对于这个子集所包含的静态类型检查的难题同样是字节码检查器所面对的。
我们最困难和最花费时间的工作在于如何高效地处理子程序。子程序是java语言层面上主要用于允许高效的实现try-finally结构。我们通常方法去进行建模和类型检查的子程序是基于由Stata 和Abadi[SA98a]开发的类型系统。即使有着之前工作的成果和技术,但是扩展这个类型系统和并且去证明可以包括健全的类型检查,其中有异常,对象初始化,和其他JVML的元素,仍然是很有挑战性的。
void f()
{
try {
something();
}
finally {
done();
}
}
图一:用try-finally的方法
Method void f()
// try代码块
0 aload_0 // load this
1 invokevirtual #5 lt;Method void something()gt; // call something()
4 jsr 14 // execute finally code
7 return // exit normally
// exception handler for try block
8 astore_1 // store exception
9 jsr 14 // execute finally code
12 aload_1 // load exception
13 athrow // rethrow exception
// subroutine for finally block
14 astore_2 // store return address
15 aload_0 // load this
16 invokevirtual #4 lt;Method void done()gt; // call done()
19 ret 2 // return from subroutine
Exception table:
From to target type
0 4 8 any
图2 将图1的程序转化为JVML
Method void f()
// try block
0 aload_0 // load this
1 invokevirtual #5 lt;Method void something()gt; // call something()
// first copy of subroutine
4 aload_0 // load this
5 invokevirtual #4 lt;Method void done()gt; // call done()
8 return // exit normally
// exception handler for try block
9 astore_1 // store exception
// second copy of subroutine
10 aload_0 // load this
11 invokevirtual #4 lt;Method void done()gt; // call done()
14 aload_1 // load exception
15 athrow // rethrow exception
Exception table:
from to target type
0 4 9 any
图3 未使用子程序所编译得到的JVML
检查器的实现基于当前的java虚拟机规范[LY96],但是似乎对子程序固有的静态分析所处理的复杂性表现并不好。例如,一系列公开的bug,其中一些导致了潜在的安全漏洞,这可能是由于早期的Sun公司的检察器没有正确的检察子程序以及和它们交互的JVML片断。
鉴于检查器在java范例中扮演着重要角色和详述和实现对于子程序的核实方法中存在的很多困难,那么我们会很自然的问这么一个问题,到底这个使用子程序所带来的便利真的值得规范和实现所付出的巨大代价吗?在java程序中,删去子程序并不会影响语义。唯一不同的将会是对于try-finally 或者其他用了子程序的代码块所使用的编译策略。最直接的方式编译try-finally语句块(没有使用子程序)就会使用一部份冗余代码,在最差的情况下这有可能带来指数级的代码量增长。显然,在JVML移去子程序,会大大简化了检查器,以及JVM其他部份的实现。例如垃圾回收器[ADM98]。然而,我们不知道有其他研究对于经典的JAVA程序使用数据去量化采用子程序的效益和使用子程序所带来的实际的节省的空间有多大。
在这篇论文中,我们在这三个方面检察由子程序带来的影响:1.字节码检查器的规范和实现;2.JVM其他与之相关的部份的实现;3.编译后的代码量。我们分析显示,使用子程序所节省的空间可以忽略不计,而那种指数级的爆炸增长并没有在实验中发生。但是由于加入子程序使得检察器的和JVM其他部份实现的复杂度远远大于使用子程序带来的任何一种效益。
第二部份描述了java字节码子程序是如何用于编译java程序的以及使用它们为何在检查程序时会发生困难。第三部份呈现了衡量子程序带来的效益以及代价。第四部份则对实验结果进行讨论以及作出评价。
- 字节码子程序
这一节描述JVML子程序和Java语言是如何构造以及去实现try-finally语句块。
我们也会讨论子程序如何被用于同步语句块和最后描述当使用子程序时,检查器对字节码检查所遇到的主要困难。
2.1 try-finally 语句块
当编译finally分句的异常处理时,子程序就是为了空间节省而设计的。关于java异常处理的细节出现在[GJS96].子程序和调用的方法共用同一个活动记录,它们可以在同一方法中被作意调用,使得所以拥有finally代码的地方在执行时必须跳转到一个包含其中处理代码的单一方法中。而没有子程序的话,finally代码块中的异常处理就必须在每一个可能离开处理块的点复制代码,或者使用更复杂的技术。
图1包含一个简单的程序,它使用了try-finally语句块。有两种离开这个异常处理块的方式,要么执行到try语句块的末尾要么有异常抛出。在这两种方式,finally语句块都会被执行。图2表明图一程序所转换得到的字节码代码。在这两个可能退出try块的点,jsr指令被用于将控制跳转到第14行,即finally子程序的开始。作为跳转动作的一部份,返回地址压入操作数栈。当ret执行返回动作时导致了返回地址被存到一个本地变量中。
没有使用子程序时,最简单的方式去编译这种try-finally语语块的方式是去复制finally中的代码块,例如第4行到第9行的代码。图3展示图1所示的源程序转换成java字节码的样子 (不使用子程序)。大多数情况下,删去一个子程序和用这种方式复制代码会造成的代码膨胀,甚至在大量调用子程序的时候,情况会更糟。然而,这种情况下,即一个子程序调用另一个子程序时,没有用子程序的话在深层嵌套调用时会使代码量爆炸式增长。而子程序嵌套会发生在当一个try-finally语句放置在finally块中时候。
也有其他的实现策略,删去子程序使得在当它们发生嵌套时会表现得更好。我们会在附录A简短地讨论其中的一种。正如我们下面所展示的,直接的转换策略似乎是最合适于现实中所有出现的情况,而且并不需要复杂的实现技术。
2.2 Synchronized语句块
子程序已经被证明在同步语句块中起作用。一个同步的例子在图4展示。在while循环体中,函数若要执行被synchronized 语句块所保护的代码必须先请求对象o的锁。这个锁必须在同步语句块结束后释放,当然在任意一点可能退出同步语句块的地方也必须这样做。在图4,这些释放锁的点就有包括continue和break语句,以及在语句块中抛异常的地方。一个子程序被用于避免复制代码去释放对象o身上的锁和它们被用于try-finally语句块是极其相似的。
void g(Object o)
{
while (true)
{
synchronized(o)
{
if (test())
continue;
else
break;
}
}
}
图4 同步语句块中有多个出口
2.3 检查子程序
子程序机制的灵活性使得关于子程序在子节码级别上的检察出现困难主要有两个原因:
1.子程序相对于本地变量是多态的。这是字节码系统的一个技术特点,即检查器所要面临解决。多态是需要允许子程序被程序中的某一点调用,而这个点中的不同类型的值存储在相同的本地变量中,只要他们类型一致,即符合子程序所使用的本地变量类型[LY96]。
2.子程序可能调用其他子程序,只要调用栈规则允许的。换句话说,最近调用的子程序必须最先返回。一个子程序可能在一些情况下,返回它的调用者的调用者。或者甚至在调用栈更远的地方。这种情况会在明确返回句语所引发,也会被隐式地执行到分支指令或者捕获到异常时所引发。
因为这个程序自己存储和操作返回地址,检查器不能假设多态变量和返回值被正确使用。因此,它必须在每个方法中就上面两个特点都做检查。否则,一个程序可能通过隐式的子程序调用栈而执行任意跳转的指令跳回到非法的返回地址。正如我们下面所展示的,这些检查构成了静态检查系统的主要部份以及对于我们所开发的JVML中健装性证明,并且它们很难在真实的检查器中实现正解的检查。
3、子程序的代价以及作用
这部份描述了测量和分析当子程序加入JVML中所带来的代价以及效益。这包括一些是定性的方面,但是我们尽可能的得到定量的结果。我们首先讨论一些在检查器上的标准和对子程序的检查上的实现的困难。这些讨论将会主要基于我们的在开发类型系统和对JVML的大型子集健壮性证明的经验。我们也会涉及到子程序对Java虚拟机其他部份实现的影响。第三部份衡量了使用子程序后,在各种各样的程序中,子程序出现的频率以及使用子程序所节省的空间。
3.1 字节码检查器的标准
作为项目的一部分,阐明最初的Java虚拟机规范和为中间语言研究静态分析技术,我们已经开发一个正式规范的JVML子集形式的类型系统。我们在这个过程中完成该系统的健装性证明。这部份通过一些较为粗略的数值衡量对关于类型系统加入子程序的代价进行分析。在呈现现数据之前,我们先给我们的形式系统作个简短的概述。
我们的工作基于Stata和Abadi,他们是最初研究JVML的子集的人,其子集仅仅包括基本的操作和子程序。尽管在扩展他们的工作,其中包括对象初始化,已经有一些成功的经验[FM98],而我们现在研究大量的JVML片段。这些片段包括:
1.类,接口,和对象
2 构造器和对象初始化
3 实例和接口方法
4 数组
5 异常和子程序 剩余内容已隐藏,支付完成后下载完整资料
资料编号:[153864],资料为PDF文档或Word文档,PDF文档可免费转换为Word
您可能感兴趣的文章
- 饮用水微生物群:一个全面的时空研究,以监测巴黎供水系统的水质外文翻译资料
- 步进电机控制和摩擦模型对复杂机械系统精确定位的影响外文翻译资料
- 具有温湿度控制的开式阴极PEM燃料电池性能的提升外文翻译资料
- 警报定时系统对驾驶员行为的影响:调查驾驶员信任的差异以及根据警报定时对警报的响应外文翻译资料
- 门禁系统的零知识认证解决方案外文翻译资料
- 车辆废气及室外环境中悬浮微粒中有机磷的含量—-个案研究外文翻译资料
- ZigBee协议对城市风力涡轮机的无线监控: 支持应用软件和传感器模块外文翻译资料
- ZigBee系统在医疗保健中提供位置信息和传感器数据传输的方案外文翻译资料
- 基于PLC的模糊控制器在污水处理系统中的应用外文翻译资料
- 光伏并联最大功率点跟踪系统独立应用程序外文翻译资料
