将异常作为正常控制流进行处理的方法和装置 本发明一般地涉及用于提高软件应用程序的性能的方法和装置。更具体地,本发明涉及用于将异常作为计算机程序的正常控制流的一部分来处理的方法和装置。
在提高与执行计算机程序相联系的效率的努力中,许多计算机程序被“优化”。优化计算机程序一般用于消除计算机代码的实质上未使用的部分。另外,优化计算机程序可以重新构造计算操作,使得整个计算更有效地执行,从而消耗更少的计算机资源。
优化器被安排为将一个计算机程序、例如以诸如C++、FORTRAN或Java字节码的程序设计语言写成的计算机程序有效地变换成一个更快的程序。更快或优化的程序一般包括基本上所有与初始或预先变换地计算机程序相同的、可观察得到的行为。更具体地,优化器包括与其相联系的初始程序相同的数学行为。然而,优化程序一般以更少的计算重新产生相同的数学行为。
优化器一般被安排为处理与计算机程序相联系的异常。如本领域普通技术人员所了解的,异常一般是要求在正常控制流之外处理的事件或条件。如名字“异常”所隐含的,意指信号稀少的或异常的事件。虽然程序有可能在其正常处理中采用异常,但对异常的处理通常与稀少差错条件相联系。与计算机程序相联系的异常一般或者涉及阵列范围检查,或者涉及无效指针访问。
在计算机程序中实施范围检查以确定一个阵列的引用是否位于该阵列的边界内。在计算机程序中可以包括专用代码来处理一个范围检查。当阵列引用不在阵列的边界内时,可以产生一个异常来表明该引用在阵列的边界之外。
无效指针引用一般涉及使用不指向任何有效存储单元的指针。在一些程序设计语言中,例如,在由加利福尼亚的Palo Alto的SunMicrosystems公司开发的JavaTM程序设计语言中,指针或者指向一个有效存储单元,或者是一个空值。当引用一个空指针时,投出一个异常。在一些情况下,可能会出现对空指针的冗余测试、即“空检查”。当第一测试表明指针不是空值时,则被安排为测试指针是否是空值的第二测试是冗余测试。如本领域普通技术人员所了解的,在试图加载与指针相联系的内容时,对空指针的测试被隐含地执行。
图1a是包括加载指针的命令并因此隐含地包括空检查的源代码的图解表示。源代码102包括将与指针相联系的内容加载进寄存器的命令或指令。举例来说,命令103是通过指针“ptrl”加载字段“A”的内容的命令。当这种命令出现时,中央处理单元[CPU]硬件进行检查以确定该指针是否是有效指针。对于JavaTM程序设计语言,只有无效指针是空指针。因此,由CPU硬件检查进行的检查在实质上是对空指针的检查。命令104也是通过指针“ptrl”进行加载的命令。虽然相对于命令103就指针“ptrl”是否为空通常已经作出了确定,但相对于命令104通常还对指针“ptrl”是否为空进行一个实质上冗余的检查。将源代码102提供给用于优化源代码102的优化器106。一旦完成了优化过程,则生成与源代码102相联系的机器代码110。
当响应于空指针的识别投出一个异常时,一般访问一个表来处理该异常。这种表常常是将异常类型映射到一个用于处理异常的合适的代码段的查找表。图1b是处理异常和访问查找表以处理异常的代码的图解表示。代码表示152包括被安排为投出不同类型的异常的调用。对投出“真异常”的函数的调用154产生一个被访问的查找表160。更具体地,“真异常”用作为进入查找表160的索引,使得适当的代码段与“真异常”的投出相联系。如图所示,代码段157最终由调用154访问。同样,对投出“假异常”的函数的调用156通过查找表160映射到代码段158。
一般来说,每次投出一个异常时,例如,每次对投出“真异常”的函数进行调用时,则将存储器定位到一个异常对象。也就是说,为投出的每个异常产生一个异常对象。如同本领域普通技术人员所了解的,这种异常对象经常从来不用。然而,异常对象被认为是在使用的,并因此不由优化器在优化过程中消除。因此,初始化异常对象的时间以及由异常对象所占据的存储空间实际上被浪费了,因为可能不会为替换的使用重新分配存储空间。
在诸如JavaTM程序设计语言的程序设计语言中,一般需要精确的异常处理。精确的异常处理一般要求异常检查既不被重新排序也不被移去。如此,则冗余代码常常与对异常、例如如上所述的空指针异常的处理相联系。
虽然专用异常处理代码在处理异常中是相对有效的,但由于处理异常的代码常常是冗余的,所以包括异常处理代码的源代码的优化可能是不完全的。换句话说,优化过程可能不会产生尽可能多地被优化的程序。当程序未被完全优化时,该程序可能不会高效地执行。此外,如上所述,每次投出一个异常时,将存储器分配给一个异常对象。由于异常对象一般不使用,所以从冗余的异常代码生成的冗余异常对象增大了与计算机系统相联系的被浪费的存储空间量。
为了进一步优化具有精确异常的程序,优化器一般包括专用的优化技术来处理异常。这些专用技术的存在需要将自定义码增加到优化器中。这个自定义码常常是细微故障的来源。此外,这种自定义码常常不能很好地集成进优化器的其他部分,并且不能去除如果优化器的全部能力都被运用的话则可以去除的某些异常检查。
因此,希望有一种用于处理异常的有效的方法。更具体地,需要一种通过使优化器能将异常作为正常程序控制流的一部分来处理而基本上消除冗余异常检查的方法和装置。
本发明涉及将异常作为正常程序控制流的一部分进行处理。依据本发明的一个方面,用于处理在基于对象的系统中的异常的方法包括获得源代码,其中所述源代码包括被安排为明确地指明关于一个异常检查的指令的代码段。所述方法还包括通过去除一个与异常检查相联系的调用来至少部分地生成源代码的一个最终内部表示,并产生与最终内部表示相联系的机器代码。在一个实施例中,所述方法还包括执行所述机器代码。
通过将异常处理集成进正常程序控制流,可以提高处理异常的效率。例如,作为正常程序控制流的一部分被处理的异常可能具有由去除在正常控制流中的冗余检查的机构所消除的冗余的检查。另外,当异常作为正常程序控制流的一部分被处理时,会消除从未使用过的异常对象,即,优化器已经去除了未使用的代码,并且,采用本发明还可以去除与异常相联系的代码,从而释放与该异常对象相联系的资源。
依据本发明的另一个方面,一种用于生成带有与异常相联系的代码部分的源代码的表示的方法包括首先获得源代码。源代码包括嵌套在第二代码部分内的第一代码部分。就第一代码部分相对于第二代码部分而言是否是冗余的进行判决,并执行一个变换来将源代码变成内部表示。这种源代码到内部表示的变换包括当确定出第一代码部分相对于第二代码部分为冗余时从源代码消除第一代码部分。在一个实施例中,进一步将内部表示变换成机器码。
在阅读了下列详细说明并研究了各个附图之后,本发明的这些和其他优点将变得明显。
通过参考下面结合附图进行的详细说明,可以更好地理解本发明,其中:
图1a是隐含地包括由优化器产生的、与源代码相联系的空检查和机器代码的源代码的图解表示。
图1b是处理作为其正常执行的一部分的异常的机器代码的图解表示。
图2是依据本发明的一个实施例的优化器的操作的图解表示,当优化器在一个使用异常的程序上操作时该优化器将异常处理集成进正常程序控制流。
图3是显示依据本发明的一个实施例的与优化具有隐含异常流的源代码相联系的步骤的过程流程图。
图4是已经由依据本发明的一个实施例的优化器处理的具有隐含异常流的计算机程序的图解表示。
图5是适合于实施本发明的通用计算机系统的图解表示。
图6是由图5的计算机系统支持的、适合于实施本发明的虚拟机的图解表示。
在诸如由加利福尼亚的Palo Alto的Sun Microsystems公司开发的JavaTM程序设计语言的程序设计语言中常常需要精确的异常处理。精确的异常处理通常要求不将异常检查重新排序或去除,除非可以证明在一特定区域不会出现异常,并且要求要实施的专用异常处理代码。对于每个异常,可能需要被安排为处理该异常的代码。因此,冗余代码常常与一个异常、例如空指针异常的处理相联系。例如,在一特定指针是否为空的测试中,如果该测试出现在已经确定了该特定指针不为空之后,则存在冗余代码。本领域普通技术人员将会理解,空指针通常是不引用存储器而是相反包含一个空值的指针。当引用一个空指针时,则投出一个异常。
当已经确定一特定指针不是空指针时,则处理冗余异常处理代码以确定指针是否为空既是不必要也是低效率的。虽然专用异常处理代码在处理异常中是相对有效的,但一般不认为包括冗余异常处理代码的源代码的优化是完全的。也就是说,这种源代码还可以进一步地优化。当一个程序未被完全优化时,该程序可能会有些低效率地执行。
通过将异常处理指令隐含地包括在计算机程序的正常控制流中,计算机程序可以由优化器进行变换,以去除与冗余异常的处理相联系的指令。换句话说,将异常处理指令隐含地编码进计算机程序使得计算机程序能被优化,以去除冗余异常处理代码。进一步地,将异常处理集成进计算机程序的正常流使得当异常被投出以便在优化过程中被去除时能产生对象。因此,从具有集成的异常处理的程序产生的机器代码一般比从具有专用异常执行代码的程序产生的机器代码更高效地执行。
图2是依据本发明的一个实施例将异常处理集成进正常程序控制流的优化器的图解表示。隐含地指明异常流、例如与处理一个异常相联系的程序流的源代码202作为优化器222的一个输入来提供。优化器222一般被安排为将源代码202变换成在数学计算上等效于源代码202的机器代码242。
在所述实施例中,优化器222根据一种语言、例如JavaTM程序设计语言生成源代码202的中间内部表示226。中间内部表示226可以被认为是源代码202的“文字”表示,因为与中间内部表示226相联系的程序流是未被充分优化的。中间内部表示226包括对用于投出异常的函数的调用228。这种函数可以访问一个查找表,该查找表将一特定异常映射到一个与该特定异常相联系的代码段。在一个实施例中,可以将这种查找表映射变换成常规的“goto”命令。
优化器被安排为使得它可以将额外的“goto”命令作为其正常处理的一部分去除出去。另外,优化器222对中间内部表示226进行优化,使得可以将未使用的、例如死代码从最终的内部表示230中排除出去。最终内部表示230由优化器222用来生成机器代码242。如图所示,在中间内部表示226中出现的调用228被从最终内部表示230中去除出去,而仍然使得最终内部表示230能够是中间内部表示226的计算等效。换句话说,最终内部表示230是中间内部表示226的一个有效简化。通过消除对投出异常的函数的调用228,响应于投出的异常而生成的未使用的异常对象可以被充分地消除。
下面参看图3描述依据本发明的一个实施例与生成机器代码的过程相联系、将异常处理集成进正常控制流的步骤。生成机器代码的过程300在步骤302开始,由优化器获得具有隐含异常流的程序。下面将参考图4描述具有隐含异常流的程序的一个例子。
在优化器获得该程序后,则在步骤304生成程序的中间内部表示。一般地,程序的中间内部表示使得所有隐含异常流变得明确,并包括明确异常检查。另外,中间内部表示包括对异常处理程序的调用。在步骤306,中间内部表示被优化。在优化过程中,除了其他优化,优化器基本上去除所有冗余异常检查和与对异常的调用相联系的死代码。也就是说,优化器通过去除未使用的代码来优化中间内部表示。其他优化包括执行与异常投出相联系的表查找以及将投出指令变换成“goto”指令,但并不仅限于这些。
过程流从步骤306进行到步骤308,在这里,从中间内部表示生成该程序的最终内部表示。如本领域普通技术人员所了解的,在从相应的中间内部表示去除未使用代码或死代码时,产生最终内部表示。如同上面参考图2所述的,最终内部表示将异常处理集成进正常控制流。在步骤308生成程序的最终内部表示之后,优化器则从最终内部表示生成机器代码。一旦产生了机器代码,则生成将异常处理集成进正常控制流的生成机器代码的过程。
如上所述,用于以隐含异常流优化计算机程序的优化器使得冗余异常检查被消除。图4是依据本发明的一个实施例的具有由优化器处理以去除冗余异常的明确异常流的计算机程序的图解表示。优化器410一般被安排为从源代码402消除未使用代码部分,以便优化与机器代码420、即由优化器410产生的机器代码相联系的性能。另外,优化器410一般检查在源代码402内执行的计算,并去除被证明为不需要、例如冗余的计算。
明确地指明异常流的源代码402包括在发现指针“ptrl”为空指针时投出一个异常的指令404。当确定指针“ptrl”不是一个空指针时,则作为与源代码402相联系的正常控制流的一部分来处理另外的指令406、408。指令408是对指针“ptrl”是否是空指针的冗余测试,因为当指令404导致确定出指针“ptrl”不是空指针时只有以正常控制流才能到达指令408。优化器410用于确定在有指令404的情况下指令408是不需要的。一旦优化器410确定出指令408是一个冗余指令,则优化器410可以消除指令408,并生成机器代码420。在机器代码420中,寄存器RZ的加载被提升在寄存器RY的加载之上,从而使相对慢的划分(DIV)指令较早地开始执行。这允许RY的加载和划分指令在时间上相互重叠,生成一个更快的程序。如上面参考图3所讨论的,在一个实施例中,优化器410还将异常处理集成进内部表示(未显示)的正常控制流中,并因此集成进机器代码420中。
图5显示了适合于实施本发明的典型通用计算机系统。计算机系统1030包括与存储设备相连的任何数目的处理器1032(也被称为中央处理单元或CPU),存储设备包括主存储设备1034(一般是随机存取存储器或RAM)和主存储设备1036(一般是只读存储器或ROM)。
计算机系统1030,或更具体地,CPU 1032可以用于支持一个虚拟机,这将为本领域普通技术人员所了解。下面将参考图6描述在计算机系统1030上支持的虚拟机的一个例子。如同本领域所公知的,ROM用于将数据和指令单向传递给CPU 1032,而RAM一般用于以双向方式传递数据和指令。CPU 1032一般可以包括任何数目的处理器。主存储设备1034、1036都包括任何合适的计算机可读介质。次级存储介质1038一般是大型存储设备,也与CPU 1032双向相连,并提供另外的数据存储容量。大型存储设备1038是可以用于存储包括计算机代码的程序、数据等的计算机可读介质。大型存储设备1038一般是诸如硬盘或磁带的存储介质,一般要比主存储设备1034、1036慢。大型存储器存储设备1038可以采取磁带或纸带阅读器或其他一些公知设备的形式。应该理解,在适当的情况下,保留在大型存储设备1038内的信息可以以标准方式被包含在作为虚拟存储器的RAM 1036的一部分中。专用主存储设备1034、例如CD-ROM也可以将数据单向地传送给CPU 1032。
CPU 1032还与一个或多个输入/输出设备1040相连,输入/输出设备1040可以包括各种设备,例如视频监视器、跟踪球、鼠标、键盘、麦克风、触摸敏感显示器、换能卡阅读器、磁带或纸带阅读器、图形输入板、触针、声音或笔迹识别器或其他公知的输入设备,例如其他计算机,但并不限于这些。最后,CPU 1032可选地采用在1012所示的网络连接与计算机或电信网络、例如局域网、因特网或内联网相连。采用这样的网络连接,可以预期,CPU 1032可以在执行上述方法步骤期间从网络接收信息或向网络输出信息。这种常常被表示为指令序列以便用CPU 1032执行的信息可以例如以包含在载波中的计算机数据信号的形式从网络接收和输出到网络。上述设备和材料对于计算机硬件和软件领域中的普通技术人员来说都是熟悉的。
如上所述,虚拟机可以在计算机系统1030上执行。图6是由图5的计算机系统1030支持的、适合于实施本发明的虚拟机的图解表示。在执行一个计算机程序、例如以由加利福尼亚的Palo Alto的SunMicrosystems公司开发的JavaTM程序设计语言写成的计算机程序时,将源代码1110提供给编译时间环境1105内的编译器1120。编译器1120将源代码1110翻译成字节代码1130。一般地,在由软件开发者生成源代码1110时将源代码1110翻译成字节代码1130。
字节代码1130一般通过网络、例如图5的网络被复制、下载或分布,或存储在存储设备、例如图5的主存储器1034上。在所述实施例中,字节代码1130是与平台无关的。也就是说,字节代码1130可以基本上在运行合适的虚拟机11140的任何计算机系统上执行。例如,在JavaTM环境中,字节代码1130可以在运行JavaTM虚拟机的计算机系统上执行。
将字节代码1130提供给一个包括虚拟机1140的运行时间环境1135。运行时间环境1135一般可以采用诸如图5的CPU 1032的处理器来执行。虚拟机1140包括编译器1142、解释器1144和运行时间系统1146。字节代码1130一般可以被提供给编译器1142或解释器1144。
当字节代码1130被提供给编译器1142时,如上所述,将字节代码1130中包含的方法编译成机器指令。另一方面,当字节代码1130被提供给解释器1144时,将字节代码1130一次一个字节代码地读入解释器1144。解释器1144然后在每个字节代码被读入解释器1144时执行由每个字节代码定义的操作。一般地,解释器1144基本上连续地处理字节代码1130并执行与字节代码1130相联系的操作。
当从操作系统1160调用一个方法时,如果确定出该方法将要作为所解释的方法被调用,则运行时间系统1146可以从解释器1144获得该方法。另一方面,如果确定出该方法将要作为所编译的方法被调用,则运行时间系统1146激活编译器1142。编译器1142则从字节代码1130产生机器指令,并执行机器语言指令。一般地,当虚拟机1140结束时,舍弃机器语言指令。
虽然只描述了本发明的几个实施例,应该理解,在不偏离本发明的精神或范围的情况下,可以以许多其他特定方式实施本发明。例如,涉及从指定明确异常流的源代码生成机器代码的步骤可以被重新排序、去除或添加。一般地,在不偏离本发明的精神和范围的情况下,涉及本发明的方法的步骤可以被重新排序、去除或添加。
虽然已经在总体上结合JavaTM环境描述了作为计算机程序的正常控制流的一部分的异常处理,但应该理解的是,这种异常处理可以在任何合适的环境中实施。例如,可以实施与其他虚拟机相联系的环境来代替与JavaTM虚拟机相联系的环境。因此,该例子被认为是例示性而非限制性的,本发明并不限于这里所给出的细节,而是可以在附带的权利要求书的范围内进行修改。