专利名称:将本机接口函数调用转换为更简单操作的方法和系统的制作方法
技术领域:
本发明涉及改进的数据处理系统。具体地,本发明涉及数据处理系统中的Java本机函数调用。更具体地,本发明涉及在数据处理系统中将Java本机接口函数调用转换为常数、内部编译器操作或更简单的操作。
背景技术:
Java是一种面向对象的编程语言和环境,其专注于将数据定义为对象以及可应用于这些对象的方法。Java仅支持单继承,这意味着每个类在任何给定时间仅能从一个其他类继承。Java也允许创建被称为接口的完全抽象的类,这种类允许定义可与若干类共享的方法,而不管其他类如何处理这些方法。Java提供了分发软件和扩展Web浏览器的能力的机制,因为程序员能编写小应用程序一次,而该小应用程序能在Web上的任何Java使能的机器上运行。
Java虚拟机(JVM)是一种虚拟计算机组件。JVM允许Java程序在不同平台上被执行,而不是仅在为其编译代码的一个平台上被执行。Java程序是为JVM编译的。以这种方式,Java能够支持用于很多类型的数据处理系统的应用,这些数据处理系统可包含多种中央处理单元和操作系统体系结构。为了使得Java应用能在不同类型的数据处理系统上执行,编译器通常生成一体系结构中性的文件格式—编译的代码可在很多处理器上执行,倘若存在Java运行时系统的话。Java编译器生成非特定于具体计算机体系结构的字节码指令。字节码是由Java编译器生成并由Java解释器执行的独立于机器的代码。Java解释器是JVM中的交替地解码和执行一个或多个字节码的模块。这些字节码指令被设计为易于在任何机器上解释,并易于被动态地(on the fly)转换为本机机器码。
可使用开发环境,例如可从Sun Microsystems公司获得的Java开发工具包(JDK),来从Java语言源代码和库构建Java字节码。可将这种Java字节码存储为Web服务器上的Java应用或小应用程序,可通过网络将该Java应用或小应用程序从该Web服务器下载到用户的机器并在本地JVM上执行。
Java运行时环境被特别设计为限制Java应用可能对它运行于其上的系统造成的损害。这对于万维网尤其重要,在万维网上当用户访问包含Java小应用程序的网页时,Java小应用程序被自动下载和执行。一般说来,人们不想执行任意的程序;它们可能包含病毒,或者它们甚至可能本身就是潜在恶意的,而不仅是无意地携带了不受欢迎的代码。除非用户特别地允许它(通过设置到JVM的用户接口中的适当标志),Java小应用程序不能向附加的存储设备(除非可能向一特定的、受限制的区域)读或写,它也不能向存储器位置(除非向一特定的、受限制的区域)读或写。
不仅Java小应用程序是为通过网络下载设计的,标准的Java库也特别地支持客户机-服务器计算。Java语言包括用于多线程和用于网络通信的规定。与其他语言(例如C)相比,编写这样的一对程序更容易得多,一个程序在用户的计算机上本地执行并处理用户交互,另一个在服务器上远程执行并可能执行更复杂和处理器密集的工作。
尽管Java语言被设计为是独立于平台的并主要在安全环境中执行,程序员可通过Java本机接口(JNI)使用C风格的调用约定来使用主机操作系统上的编译的本机二进制代码,从而扩展Java应用。以这种方式,Java应用可具有对主机操作系统的完全访问权,包括对附加的I/O设备、存储器等的读或写。由于此,Java程序可以成为特定于平台的代价完成通过JVM通常不允许的任务。然而,使用设计良好的体系结构,Java语言程序员可干净地将独立于平台的部分隔离,并向其他Java组件呈现一干净的、独立于平台的对象API,而同时完成特定于平台的任务。
使用JNI API,位于Java虚拟机(JVM)内的参数和类数据以及由JVM提供的服务可被访问并可被修改。然而,由于JNI暴露了一非常独立于平台和不透明的JVM的表示、其数据和服务,所以存在着开销。JNI API通常是由一指向函数指针(这些函数指针指向JNI函数实现)的表的指针(被称为JNI环境指针,或JNIEnv)暴露的。虽然该指针对于JNI的平台独立性是必需的,该指针也可能是代价高昂的,因为在JNI函数调用期间执行额外的分支和表查找。JNI调用的代价取决于被调用的JNI函数的类型。
例如,为了访问从Java传递给本机代码的串和数组参数,需要对JNI函数的特殊调用。这些特殊的调用造成昂贵的运行时复制操作以避免触及JVM的数据副本。因此JNI API提供了访问器(accessor)函数,这些函数试图增加本机代码接收对底层JVM数据的直接引用的机会。然而,这些函数是根据JVM的决定实现的,并且这些函数的使用对程序员的自由施加了某些限制。
对于字段和方法访问,也要求JNI函数调用来从本机代码修改对象和访问JVM服务。例如,为了修改对象的字段或调用类的方法,必须首先检索适当数据的句柄。这种检索通常被实现为在JVM的反映(reflective)数据结构上的遍历以及在运行时昂贵的基于串的签名比较操作。这种遍历比Java中的直接字段访问慢几个数量级。此外,如果非异步的JVM正在执行阻塞(blocking)工作,则JNI函数调用可能停滞(stall)。
其他JNI函数具有类似于用于字段和方法访问的JNI函数的唯一的一组开销。这些JNI函数包括实例化对象、管理引用、处理异常、支持同步和反映的函数,以及在Java调用API中用于将JVM嵌入本机代码内的函数。
已做出了若干尝试来最小化JNI调用的开销。最初的尝试是基于程序员的优化,其形式为当编写使用JNI API的本机代码时高效的编码技术。JNI规范也提供了一组可返回对JVM数据和对象的直接引用的关键函数,并建议了避免调用JNI API的方法,例如在类的静态初始化期间缓存字段和方法ID。
另一种尝试涉及通过限制在本机代码中可提供的功能的类型来最小化对JNI API函数的依赖,从而消除与本机函数相关的开销。然而,这种机制只能用于被保证不会要求垃圾收集、异常处理、同步或任何类型的安全支持的方法,因为这些是包装器(wrapper)提供的功能类型。
在又一种最化小JNI函数调用的开销的尝试中,编译器可使用紧密耦合于VM的专有本机接口,因为该接口具有关于VM的内部结构的知识。这种编译器的一个例子是Jcc编译器,这是一种使用专有本机接口直接编译到本机代码的优化编译器,该专有本机接口令人联想到来自SunMicrosystems公司的原始的本机方法接口(NMI)。然而,该NMI已被JNI代替。在Jcc中,被标记为“本机的”Java方法将被当作这样的C方法,该C方法将使用C调用约定被调用,并对每个Java类发出一C结构。以这种方式,Jcc可内嵌短的汇编段以加速本机调用。
尽管上述各尝试最小化了与JNI函数调用相关的某些开销,但并不存在不限制在本机代码中实现的功能的类型的(如在上述第二种尝试中提及的)、或不耦合到特定VM实现的(如在上述第三种尝试中提及的)现有的机制。
因此,拥有这样的方法、装置、和计算机指令将是有利的,该方法、装置和计算机指令由即时(JIT)编译器使用以将JNI函数调用转换为常数、内部编译器操作或更简单的中间表示,从而可改进本机代码访问JVM数据和服务的性能,而不耦合到特定的VM实现或牺牲JNI的类型安全(type safety)。
发明内容
本发明提供了用于在即时编译期间将本机函数调用转换为更简单的操作的方法、装置、和计算机指令。在编译一程序以生成用于多个Java本机接口(JNI)函数调用的形状(shape)的列表后,提供一内嵌器以识别用于转换的、在本机代码中进行的本机接口函数或JNI调用的列表。
然后,即时(JIT)编译器对该本机接口函数调用列表和被传递给这些本机接口函数调用的多个变元执行定义和使用(def/use)分析。随后,提供一JIT调用转换器以使用所述定义和使用分析的结果将该本机接口函数调用列表的一部分转换为常数、内部即时编译器操作或更简单的中间表示。
在本机函数调用的内嵌期间,即时内嵌器对于在内嵌的代码中发生的每个本机接口调用确定在该调用中使用的本机接口环境变量是否位于与它在代表所有已知的本机接口调用的预定义形状的列表中所出现的相同的位置。一JNI调用的形状包括(1)访问实际目标本机接口或JNI函数的手段(以中间表示表示的)(2)每个实际变元接收到的处理(同样以中间表示表示的)。典型的JNI调用的形状(当构建形状列表时被创建的)唯一地确定实际JNI例程。如果在调用中使用的本机接口环境变量位于与在代表本机接口调用的预定义形状的列表中的形状之一中相同的位置,则内嵌器确定在该形状和由一内嵌的本机函数进行的JNI调用的中间表示之间是否存在匹配。
如果在该形状和该JNI函数调用的中间表示之间存在匹配,则内嵌器将该JNI调用添加到用于当前被内嵌的本机方法的JNI函数调用的列表中,其中该调用列表是以在该多个JNI调用的中间表示中出现的顺序排序的。
在执行了定义和使用分析之后,该即时调用转换器对于该本机接口函数调用列表中的每个本机接口函数调用确定本机接口函数调用的类型,并尝试根据每个JNI函数调用的类型将该本机接口函数调用替换为常数值、内部即时编译器操作、或更简单的中间表示。
因为新生成的常数、内部即时编译器操作、或更简单的中间表示不使用JNI而执行,它们转而提供了对Java虚拟机的服务和数据的直接的和更快的访问。
在所附权利要求中提出了相信为本发明的特点的新颖特征。然而,通过结合附图参照以下对示例性实施例的详细说明可最好地理解本发明本身以及其优选使用方式、其他目标和优点,在这些附图中图1是根据本发明的一优选实施例可在其中实现本发明的数据处理系统的图示;图2是可在其中实现本发明的数据处理系统的框图;图3是示出了在可实现本发明的计算机系统内运行的软件组件的关系的框图;图4是根据本发明的一优选实施例的JVM的框图;图5示出了根据本发明的一优选实施例由JNI调用转换器执行的JNI函数调用转换;图6示出了根据本发明的一优选实施例为JNI函数调用生成中间表示;图7示出了根据本发明的一优选实施例用于JNI转换的本机内嵌准备;图8的图示出了根据本发明的一优选实施例由编译器执行的示例性def/use分析;以及图9是根据本发明的一优选实施例用于将JNI函数调用转换为常数、内部编译器操作或更简单的中间表示的示例性过程。
具体实施例方式
现参照附图并具体参照图1,其示出了根据本发明的一优选实施例可在其中实现本发明的数据处理系统的图示。示出了一计算机100,其包括系统单元102、视频显示终端104、键盘106、可包括软盘驱动器和其他类型的永久的和可拆装的存储介质的存储设备108、和鼠标110。个人计算机100中还可包括其他输入设备,例如游戏杆、触控板、触屏、跟踪球、麦克风等。可使用任何适当的计算机,例如位于纽约Armonk的国际商业机器公司的产品IBM eServer计算机或IntelliStation计算机,来实现计算机100。虽然所示的图示示出了一计算机,本发明的其他实施例可在其他类型的数据处理系统例如网络计算机中实现。计算机100还优选地包括图形用户界面(GUI),该图形用户界面可通过存在于在计算机100中运行的计算机可读介质中的系统软件来实现。
现参照图2,其示出了可在其中实现本发明的数据处理系统的框图。数据处理系统200是一计算机例如图1中的计算机100的示例,实现本发明的过程的代码或指令可位于该计算机中。数据处理系统200使用外围部件互连(PCI)局部总线体系结构。尽管所示的示例使用PCI总线,也可使用诸如加速图形端口(AGP)和工业标准结构(ISA)的其他总线体系结构。处理器202和主存储器204通过PCI桥208连接到PCI局部总线206。PCI桥208也可包括集成的存储控制器和用于处理器202的高速缓冲存储器。可通过直接部件互连或通过附加连接器进行附加的到PCI局部总线的连接。在所示的示例中,局域网(LAN)适配器210、小型计算机系统接口(SCSI)主机总线适配器212、和扩展总线接口214通过直接部件互连连接到PCI局部总线206。相反地,音频适配器216、图形适配器218、和音频/视频适配器219通过插入到扩展槽中的附加板连接到PCI局部总线206。扩展总线接口214提供了用于键盘和鼠标适配器220、调制解调器222、和附加存储器224的连接。SCSI主机总线适配器212提供了用于硬盘驱动器226、磁带驱动器228、和CD-ROM驱动器230的连接。典型的PCI局部总线实现将支持三个或四个PCI扩展槽或附加连接器。
操作系统运行在处理器202上并用于对图2中的数据处理系统200中的各部件进行协调和提供控制。操作系统可以是商业上可获得的操作系统例如可从Microsoft公司获得的Windows XP。面向对象的编程系统例如Java可与操作系统一起运行,并提供从在数据处理系统200上运行的Java程序或应用到操作系统的调用。“Java”是Sun Microsystems公司的商标。用于操作系统、面向对象的编程系统、和应用或程序的指令位于存储设备例如硬盘驱动器226上,并可被加载到主存储器204中以便由处理器202执行。
本领域的普通技术人员将理解图2中的硬件可根据实现而变化。作为对图2中所示的硬件的附加或替代,可使用其他内部硬件或外围设备例如快闪只读存储器(ROM)、等效的非易失性存储器、或光盘驱动器等。此外,可将本发明的过程应用于多处理器数据处理系统。
例如,数据处理系统200如果可选地被配置为网络计算机,则可不包括SCSI主机总线适配器212、硬盘驱动器226、磁带驱动器228、和CD-ROM 230。在这种情况下,将被适当地称为客户端计算机的该计算机包括某种类型的网络通信接口,例如LAN适配器210、调制解调器222等。作为另一个示例,数据处理系统200可以是独立的系统,其被配置为不依赖于某种类型的网络通信接口而可引导,不管数据处理系统200是否包括某种类型的网络通信接口。作为进一步的示例,数据处理系统200可以是个人数据助理(PDA),其被配置为具有ROM和/或快闪ROM,以为存储操作系统文件和/或用户生成的数据提供非易失性存储器。
图2中所示的示例和以上描述的示例并非意在暗示结构上的限制。例如,数据处理系统200除了采取PDA的形式也可以是笔记本计算机或手持式计算机。数据处理系统200也可以是信息站(kiosk)或网络电器(webappliance)。
本发明的过程是由处理器202使用计算机实现的指令执行的,这些指令可被加载到存储器例如主存储器204、存储器224、或一个或多个外围设备226-230中。
现参照图3,该框图示出了在可实现本发明的计算机系统内运行的各软件组件的关系。基于Java的系统300包含特定于平台的操作系统302,该操作系统为在特定硬件平台上执行的软件提供了硬件和系统支持。JVM304是一个可与操作系统一起执行的软件应用。JVM 304提供了Java运行时环境,该环境具有执行Java应用或小应用程序306的能力,所述Java应用或小应用程序是以Java编程语言编写的程序、小服务程序、或软件组件。JVM 304在其中运行的计算机系统可以类似于以上描述的数据处理系统200或计算机100。然而,JVM 304可在具有嵌入的picoJava内核的所谓的Java芯片、硅上Java(java-on-silicon)、或Java处理器上的专用的硬件中实现。
在Java运行时环境的中心的是JVM,该JVM支持Java的环境的所有方面,包括其体系结构、安全特征、跨网络的移动性、和平台独立性。
JVM是一虚拟计算机,即被抽象地规定的计算机。该规范定义了每个JVM必须实现的某些特征,并具有可取决于JVM被设计为在其上执行的平台的一定范围的设计选择。例如,所有JVM必须执行Java字节码,并可使用一系列技术来执行由字节码代表的指令。JVM可完全在软件中实现或在某种程度上在硬件中实现。这种灵活性允许为大型计算机和PDA设计不同的JVM。
JVM是实际执行Java程序的虚拟计算机组件的名称。Java程序不是直接由中央处理器运行的,而是由JVM运行的,JVM本身是运行在处理器上的一个软件。JVM允许Java程序在不同的平台上执行,而不是仅在为其编译代码的一个平台上执行。Java程序是为JVM编译的。以这种方式,Java能够支持用于很多类型的数据处理系统的应用,这些数据处理系统可包含各种中央处理单元和操作系统体系结构。为了使Java应用能在不同类型的数据处理系统上执行,编译器典型地生成体系结构中性的文件格式-编译的代码可在很多处理器上执行,只要存在Java运行时系统即可。Java编译器生成非特定于具体计算机体系结构的字节码指令。字节码是由Java编译器生成并由Java解释器执行的独立于机器的代码。Java解释器是交替地解码和解释一个或多个字节码的、JVM的部分。这些字节码指令被设计为易于在任何计算机上执行并易于被动态地(on the fly)转换为本机机器码。字节码可由即时编译器或JIT转换为本机代码。
JVM加载类文件并执行其中的字节码。类文件是由JVM中的类加载器加载的。类加载器从应用加载类文件并从应用所需要Java应用编程接口(API)加载类文件。执行字节码的执行引擎可随不同的平台和实现而不同。
一种类型的基于软件的执行引擎是JIT编译器。使用这种类型的执行,在成功地满足用于JIT编译一方法的标准后,将一方法的字节码编译为本机机器码。然后用于该方法的本机机器码被缓存,并在下次调用该方法时被重用。执行引擎也可在硬件中实现并嵌入芯片中,从而字节码被本机地执行。JVM通常解释字节码,但JVM也可使用其他技术,例如即时编译,来执行字节码。
当在特定于平台的操作系统上的软件中实现的JVM上执行应用时,Java应用可通过调用本机方法来与主机操作系统交互。Java方法是在Java语言中编写的,被编译为字节码,并被存储在类文件中。本机方法是在某种其他语言中编写的,并被编译为特定处理器的本机机器码。本机方法被存储在动态链接库中,动态链接库的精确形式是特定于平台的。
现参照图4,其示出了根据本发明的一优选实施例的JVM的框图。JVM 404包括类加载器子系统402,该子系统是一用于在给定了类型的完全限定名的情况下加载类型例如类和接口的机制。JVM 404还包含运行时数据区404、执行引擎406、本机方法接口408、和存储管理410。执行引擎406是一用于执行包含在由类加载器子系统402加载的类的方法中的指令的机制。执行引擎406可以是例如Java解释器412或即时编译器414。本机方法接口408允许访问底层操作系统中的资源。本机方法接口408可以是例如Java本机接口(JNI)。
运行时数据区404包含本机方法栈416、Java栈418、PC寄存器420、方法区422、和堆424。这些不同的数据区代表JVM 404执行程序所需要的存储区的结构。
Java栈418用于存储Java方法调用的状态。当发起新的线程时,JVM为该线程创建一新的Java栈。JVM只直接在Java栈上执行两种操作它推入和弹出帧。一线程的Java栈存储用于该线程的Java方法调用的状态。Java方法调用的状态包括其局部变量、调用它所用的参数、其返回值(如果有的话)、和中间计算。Java栈由栈帧组成。一栈帧包含单个Java方法调用的状态。当一线程调用一方法时,JVM将一新的栈帧推入该线程的Java栈。当该方法完成时,JVM将用于该方法的帧弹出并丢弃它。JVM没有任何用于保存中间值的寄存器;任何需要或产生中间值的Java指令使用该栈来保存中间值。以这种方式,为多种平台体系结构良好地定义了Java指令集。
程序计数器(PC)寄存器420用于指示下一个要执行的指令。每个实例化的线程获得它自己的PC寄存器和Java栈。如果该线程正在执行一JVM方法,则该PC寄存器的值指示下一个要执行的指令。本机方法栈416存储本机方法的调用的状态。本机方法调用的状态是以依赖于实现的方式存储在本机方法栈、寄存器、或其他依赖于实现的存储区中的。在某些JVM实现中,本机方法栈416和Java栈418是结合在一起的。
方法区422包含类数据,而堆424包含所有实例化的对象。在这些示例中,常数池位于方法区422中。JVM规范严格地定义了数据类型和操作。大多数JVM选择具有一个方法区和一个堆,每一个都由运行在该JVM例如JVM 404中的所有线程共享。当JVM 404加载类文件时,它根据包含在该类文件中的二进制数据分析关于类型的信息。JVM 404将这种类型信息放入方法区。每次创建一类实例或数组,就从堆424中分配用于该新对象的存储空间。JVM 404包括一在用于堆424的存储区中分配存储空间的指令,但不包括用于在该存储区中释放该空间的指令。所示的示例中的存储管理410管理分配给堆424的存储区中的存储空间。存储管理410可包括一垃圾收集器,该垃圾收集器自动回收由不再被引用的对象所使用的存储空间。此外,垃圾收集器也可以移动对象以减少堆的碎片化。
本发明提供了在JIT编译期间用于将JNI函数调用转换为更简单的编译器操作(其最终导致生成常数和更高效的中间表示)的方法、装置、和计算机指令。在一优选实施例中,本发明利用从内嵌的本机函数中间表示转换来的JIT编译器中间表示。本发明提供了一JNI调用转换器,该转换器对每个所生成的JIT编译器中间表示指令执行分析,以寻找JNI函数调用。然后JNI调用转换器将同样多的JNI函数调用的中间表示转换为内部JIT编译器操作或常数,以便生成等价于JNI调用但不需要调用JNI函数的更简单的操作。以这种方式,提供了对JVM服务和数据的更快的访问。
为了发现程序打算调用的实际JNI方法,JNI调用转换器首先必须理解每个JNI函数调用的JIT编译器中间表示的形状。为了理解每个形状,JNI调用转换器调用JIT编译器以依次编译调用每个JNI函数的不可执行的C或C++程序。JNI调用转换器获得关于每个JNI函数如何使用JNIEnv变元和每个调用的每个用户提供变元的使用的知识,并维护已知形状的列表。作为另一种选择,JIT调用转换器可在Java程序执行的开始动态地确定形状或作为JII编译器构建过程的一部分确定形状。作为另一种选择,可将关于形状的知识硬编码到JIT编译器的源代码中。
JNI调用的形状包括(1)访问实际目标JNI函数的手段(以中间表示表示的), (2)每个实际变元接收到的处理(同样以中间表示表示的)。典型的JNI调用的形状(当构建形状列表时被创建的)唯一地确定实际JNI例程。在该优选实施例中,构建形状列表(通过处理特殊的C和C++程序)的过程发生在当该Java过程(并因此JIT)开始执行时。也可能在构造JIT本身时创建形状列表。通过执行作为构建JIT编译器的一部分的形状确定,当编译器被重启时确定某一组形状。这样,用于每个JNI函数的形状可被静态地硬编码到JIT编译器中。为了执行作为构建JIT编译器的一部分的形状确定的唯一要求是所使用的中间表示对于JIT编译器的当前版本和虚拟机两者都是正确的。作为该过程的结果,生成JNI函数调用中间表示形状的列表。
一旦形状被确定,它们将由内嵌器使用,该内嵌器执行这样的内嵌工作,包括将参数映射为变元,合并本机编译器中间表示和JIT编译器中间表示,控制流图,和具体化JNIEnv指针从而内嵌的语句可使用它来进行对JNI API的调用。
在本机代码的内嵌期间,内嵌器分析内嵌的代码以发现所生成的代表JNI调用的中间表示语句。它通过将内嵌的中间表示匹配于从C或C++程序生成的或在JIT构建过程中生成的形状的列表来进行上述分析。内嵌器记录在内嵌的本机函数中的、可被传递给递归内嵌的函数的JNIEnv变量的所有使用。当内嵌器遇到JNIEnv变量的一使用时,如果该JNIEnv变量未被用于与它在所述形状列表中的任何形状中所出现的相同的位置,则内嵌过程继续。然而,如果该JNIEnv变量被用于与它在所述形状列表中的一个形状中所显示的相同的位置,则将该整个形状匹配于该JNI函数调用点(callsite)的中间表示。如果(一JNI方法调用的)形状与形状列表的一成员相比具有相同数量的变元,并且实际调用中的每个变元与形状列表中的该成员中的变元的类型一致,则该形状匹配形状列表中的该成员。如果发现匹配,这意味着该调用点对应于一JNI函数调用,则该调用点不适合于内嵌,但可适合于转换。
在这种情况下,JIT编译器内嵌器记录它确定对应于JNI函数调用的调用点。生成这种JNI函数调用的一列表,该列表是按照在用于该内嵌方法的中间表示中出现的顺序排序的。如果一个方法调用使用另一个方法调用的结果,则最内的方法在该列表中将出现在该结果的使用之前。一旦完成了调用点的分析,则内嵌器识别不可内嵌的但可能可转换的JNI函数调用的列表。然后JNI调用转换器使用JNI def/use分析的结果对该JNI函数调用列表执行转换。
若干JNI函数调用被用于识别通常通过类的常数池来识别的元素。这些JNI函数的例子包括getObjectClass、getMethodID、和getFieldID。其他JNI函数调用可执行更具体的动作,例如获得或设置对象字段值。然而,在可执行优化之前必须知道被传递给JNI函数的对象的特定类型。因此,执行JNI def/use分析。
JNI def/use分析类似于在优化编译器中经常使用的得到深入理解的定义/使用分析,它是通过跟踪通过内嵌的代码被传递给内嵌的本机方法的对象到它们作为变元被传递给JNI函数的位置来执行的。每个变元由一组可能的对象代表,该组对象取决于从内嵌的本机方法的开始到JNI函数的调用的控制流。该组对象可包括多于一个元素,并且这些元素可都来自相同的类。
def/use分析计算到达JNI函数调用中的使用的所有可能的类、字段和方法。就是说,当它不能在一JNI调用点处决定性地确定例如一对象一定是其实例的类,则它产生足够的信息以允许该转换阶段考虑该对象可能是其实例的所有可能的类。
有可能def/use分析不能计算甚至有条件的结果。这将在例如一JNI函数调用的变元是从存储器中取出(已由先前的过程写在那里)以用于随后的JNI函数调用的情况下发生。
在JNI def/use分析中,getObjectClass、getSuperClass、findClass、getMethodID、和getFieldID被当作定义,并且它们的使用被跟踪。结果通常可被转换为将被使用以代替通常的常数池索引的常数值。
此外,JNI def/use分析也跟踪findClass、getMethodID、和getFieldID的串变元。以这种方式,JIT编译器可确实地解析(resolve)这些调用中的某一些,而更天真的实现将不能这样做。然而,JNI def/use分析的一个复杂之处是NewObjectType JNI调用的结果可到达在JNI函数调用的列表中的对象的多种使用。因此,这些结果具有一抽象类型,该抽象类型可在JNI def/use阶段期间用作NewObjectType的变元的类和MethodID变得固定的情况下变得具体。
如上所述,JNI调用转换器使用JNI def/use分析的结果对JNI函数调用列表执行转换。在转换期间,JNI调用转换器对JNI函数调用列表进行迭代,并将JNI函数调用替换为常数值,或生成新的更简单的JIT编译器中间表示并将JNI函数调用替换为该新的JIT编译器中间表示。
取决于JNI函数调用的类型,该转换过程的可能结果可以是不同的。例如,如果到达getObjectClass的所有可能的定义是同一类的,则该调用被替换为适当的常数。如下所述,在def/use分析产生包括关于到达getObjectClass的多个不兼容的(对象的)类的信息的已知结果的情况下,使用条件逻辑和代码复制(code replication)来使正确的实际类可用于随后的使用。
如果到达getFieldID或getMethodID的所有可能的类是兼容的(在Java的意义上),并且串变元可被唯一地确定,则该调用被替换为适当的常数。(如果不兼容的类的对象到达getFieldID或getMethodID,则可如下所述插入条件逻辑。)如果到达get<type>Field方法或put<type>Field方法(它们检索或存储一Java类的字段)的所有可能的fieldID是相同的,并且到达该调用的所有可能的对象是兼容的类类型,则该调用被替换为相应的JIT编译器的中间表示的序列。应注意这种形式的内部表示根据用于执行本机方法的Java规则推迟了抛出任何异常。(表示法get<type>Field指意在从一对象检索字段的任何JNI API函数,并且<type>表示法的其他使用也类似。熟悉JNI API的技术人员将容易理解这种表示法。)对于JNI函数列表中的各种call<type>Method JNI函数调用,通过移除被调用的方法的中间表示,并生成直接调用该函数的JIT中间表示,来执行类似的转换。对于JNI函数列表中不是使用以上步骤处理的任何条目,该调用被当作对适当的VM服务例程的普通调用。
重要的是注意到,对于上述任何函数,如果JNI def/use阶段产生了已知的但不是决定性的信息,则将基于传递到JNI函数调用中的实际接收器对象的类型或实际值(即,jfieldID或jmethodID)的条件逻辑与适当的中间表示一起插入以代表被转换的特定JNI函数的语义。
现转向图5,该图示出了根据本发明的一优选实施例由JNI调用转换器执行的JNI函数调用转换。如图5所示,本发明提供了JNI调用转换器500。
JNI调用转换器500在由内嵌器内嵌的每个JIT编译器中间表示指令502中进行迭代。某些JIT编译器中间表示指令502可能是利用了JNI API函数的JNI函数调用504。
对于那些是JNI函数调用的指令,JNI调用转换器500将这些指令转换为转换的调用506和内部JIT编译器操作508。转换的调用506可以是提供对JVM服务和数据的更直接和更快的访问的更简单的JIT编译器中间表示。内部JIT编译器操作508可以是常数值或不使用JNI的简化的中间表示。
以这种方式,JNI调用转换器500修改某些或很多JNI函数调用以消除实际调用JNI函数的需要。该转换是通过使用内嵌器进行分析而将每个JNI函数的JIT编译器中间表示的形状匹配于已知形状的列表来完成的。为了执行这种匹配,首先以如下在图6中描述的方式生成一形状列表。
现转到图6,该图示出了根据本发明的一优选实施例为JNI函数调用生成中间表示形状。如图6中所示,JIT编译器600编译包含对所有JNI函数的典型调用的不可执行的C和C++程序602并生成代表用于JNI函数调用的中间表示的形状的列表604。
现转到图7,该图示出了根据本发明的一优选实施例用于JNI转换的本机内嵌准备。
如图7所示,JIT编译器内嵌器700通过将用于本机调用的中间表示替换为JIT编译器中间表示格式的函数的实际实现来内嵌本机函数。
在内嵌期间,JIT编译器内嵌器700可分析包括若干JNI函数调用的本机函数中间表示702。在该示例中,本机函数中间表示702包括JNI调用1、JNI调用2、JNI调用3、和JNI调用4。对于由JIT编译器内嵌器匹配的每个JNI函数调用,JIT编译器内嵌器700将该JNI函数调用以其在内嵌的本机函数的中间表示702中出现的顺序添加到JNI函数调用列表704。
因此,JNI调用1被添加到JNI函数调用列表704,然后是JNI调用2。如果一个JNI函数调用使用另一个JNI函数调用的结果,则最内的调用将在该表示中首先出现。
现转向图8,该图示出了根据本发明的一优选实施例由编译器执行的示例性def/use分析。如图8所示,在JNI def/use分析中,编译器分析程序并确定是否可执行进一步的优化。
在该示例中,def/use分析确定定义了什么变量。例如,程序800包括定义对象“obj”802、整数“a”804、类“cls”806、和字段“fid”808。此外,def/use分析确定何处使用所定义的变量。例如,“obj”被用在getObjectClass方法810和SetIntField方法814中,“cls”被用在getFieldID方法812中,且“fid”被用在setIntField方法814中。因为“cls”806是getObjectClass方法810的结果,所以它被当作定义,且其使用被跟踪。在该图所示出的代码中,有可能将对GetFieldID的JNI函数调用替换为代表该字段的ID的常数值。此外,因为“fid”808也是setIntField方法814的输入变元,将有可能将用于对setIntField方法814的调用的中间表示转换为直接修改对象中的相应字段的中间表示(即,无需进行JNI函数调用来这样做)。
现转向图9,其示出了根据本发明的一优选实施例用于将JNI函数调用转换为常数、内部编译器操作或更简单的中间表示的流程图。该过程假设JNI调用转换器已如图6所示运行JIT编译器来生成JIT编译器中间表示和JNI函数调用形状列表。
如图9中所示,内嵌器被运行到其标准的内嵌阶段(步骤900)。它查看它是否遇到任何可内嵌的本机调用点(步骤902)。如果它没遇到,则它继续进行到步骤926,该步骤重新开始JIT编译的其余部分。然而,如果遇到本机调用点,则它继续到步骤904,在此它检查是否可内嵌的本机函数包含任何函数调用。如果不包含,则内嵌器继续进行到步骤924,该步骤重新开始JIT编译的其余部分。如果可内嵌的本机调用确实包含函数调用,则该过程继续到步骤906,在此将本机代码匹配于由图6中所示的过程生成的JNI函数调用形状。在步骤908,检查调用点以发现匹配,且如果发现匹配,则步骤910将该调用点添加到JNI调用列表,并继续进行到步骤912,该步骤为任何其他的调用点重复该最后过程。如果调用点不匹配,则该过程重复自身直到所有调用点已被检查。
一旦所有调用点已被分析,则步骤914执行JNI def/use分析,且通过在步骤916处理第一个被识别的JNI调用来继续。如果JNI def/use分析为该调用点产生了决定性的结果(步骤918),则该调用的中间表示被替换为常数、更简单的编译器操作或更简单的中间表示,并可能带有用于已知结果的条件逻辑(步骤922)。如果JNI def/use为该特定调用点生成了未知的结果,则从所述JNI函数调用列表中丢弃该调用点和任何其他使用其结果的调用点(步骤920)。
一旦已使用JNI def/use的结果来转换该调用点,则该过程检查另外的JNI调用点(步骤924)。如果有更多的JNI调用点,则该过程继续进行到步骤916。如果没有更多的调用点要处理,则步骤926继续进行JIT编译的其他部分,并且该过程随后结束。
重要的是注意到,尽管已在全功能的数据处理系统的情境中描述了本发明,本领域的普通技术人员将认识到本发明的过程也能够以指令的计算机可读介质的形式和多种形式被分发,并且不管实际用于执行这种分发的信号承载介质的特定类型是什么,本发明都同等适用。计算机可读介质的例子包括可记录类型的介质,例如软盘、硬盘驱动器、RAM、CD-ROM、DVD-ROM,以及传输类型的介质,例如使用诸如射频和光波传输等传输形式的数字和模拟通信链路、有线或无线的通信链路。该计算机可读介质可采取编码格式的形式,这种编码格式被解码以实际用于特定的数据处理系统。
本发明的描述是为了说明和描述的目的给出的,而非旨在是穷尽性的或限于本发明的所公开的形式。对本领域的普通技术人员来说很多修改和变形都将是显然的。例如,尽管所示的实施例是针对处理Java中的字节码,本发明的过程也可应用于处理这样的指令的其他编程语言和环境,所述指令不是特定于这些指令在其上执行的计算机。在这种情况下,该计算机上的虚拟机可解释这些指令或将这些指令发送给编译器以生成适于由该虚拟机位于其上的计算机执行的代码。
所选择和描述的实施例是为了最好地解释本发明的原理和实际应用,并使本领域的其他普通技术人员能理解本发明的带有适合于所考虑的特定应用的各种修改的各实施例。
权利要求
1.一种在数据处理系统中用于在即时编译期间将本机接口函数调用转换为更简单的操作的方法,该方法包括编译本机语言程序以生成用于多个本机接口函数调用的形状的列表;通过将在该本机语言程序中进行的多个本机接口函数调用匹配于该形状列表,来识别用于可能的转换的本机接口函数调用的列表;通过跟踪作为参数被传递给本机接口函数的多个变元的多个值,来对所识别的本机接口函数调用的列表中的每一个执行定义和使用分析;以及使用所述定义和使用分析的结果,将所述本机接口函数调用的列表的一部分转换为常数、内部即时编译器操作、和更简单的中间表示中的一个。
2.根据权利要求1的方法,其中所述形状列表包括所述多个本机接口函数调用的中间表示,并包括该多个本机函数调用对本机接口环境变量和用户变元的用法。
3.根据权利要求2的方法,其中所述识别步骤是在内嵌本机函数调用期间、响应于检测到内嵌的本机函数调用中的本机接口函数调用而执行的,且其中所述识别步骤还包括对于所述识别的本机接口函数调用列表中的每一个,确定所述本机接口环境变量是否是以在所述生成的形状的列表中的一形状中的相同方式被使用的;如果所述本机接口环境变量是以在所述生成的形状的列表中的一形状中的相同方式被使用的,则确定在该形状和该本机接口函数调用的中间表示之间是否存在匹配,其中如果该本机接口函数调用的中间表示与该形状相比具有相同数量的变元,且该本机接口函数调用中的每个变元与该形状中的变元的类型一致,则存在匹配;以及如果在该形状和该本机接口函数调用的中间表示之间存在匹配,则将该本机接口函数调用添加到所述本机接口函数调用列表,其中该本机接口函数调用列表是按照在所述多个本机接口函数调用的中间表示中出现的顺序排序的。
4.根据权利要求3的方法,其中所述定义和使用分析包括在识别了所述本机接口函数调用列表之后跟踪被传递给该本机接口函数调用列表的多个对象到该多个对象作为变元被传递给本机接口函数的位置。
5.根据权利要求4的方法,其中所述转换步骤包括对于所述本机接口函数调用列表中的每个本机接口函数调用,确定所述定义和使用分析是否返回决定性的结果;如果该定义和使用分析返回决定性的结果,则确定该本机接口函数调用的类型;以及根据该本机接口函数调用的类型,将该本机接口函数调用替换为常数值、内部即时编译器操作、和更简单的中间表示中的一个。
6.根据权利要求5的方法,还包括如果所述定义和使用分析返回已知的结果,则将所述调用点替换为包含条件逻辑的、代表所指定的调用的语义的中间表示;如果该定义和使用分析返回未知的结果,则从所考虑的本机接口调用列表中丢弃该本机接口函数调用和使用该本机接口函数调用的任何其他本机接口函数调用。
7.根据权利要求5的方法,其中所述常数、内部即时编译器操作和更简单的中间表示提供了对虚拟机的服务和数据的直接的和更快的访问,其中所述内部即时编译器操作执行其功能而不使用本机接口。
8.根据权利要求1的方法,其中所述形状列表中的形状包括以中间表示来表示的用于访问实际目标本机接口函数的手段和以中间表示来表示的每个实际变元接收到的处理,且其中该形状唯一地标识了该实际目标本机接口函数。
9.根据权利要求1的方法,其中所述定义和使用分析确定定义了什么变量以及在何处使用所定义的变量。
10.一种用于在即时编译期间将本机接口函数调用转换为更简单的操作的数据处理系统,该数据处理系统包括即时编译器,用于编译本机语言程序以生成用于该本机语言程序中的多个本机接口函数调用的形状的列表;即时编译器内嵌器,用于从该形状列表中识别用于可能的转换的本机接口函数调用的列表;其中该即时编译器对所述本机接口函数调用的列表和被传递给所述本机接口函数的多个变元执行定义和使用分析,其中该定义和使用分析确定定义了什么变量,以及在何处使用所定义的变量;以及即时调用转换器,用于使用该定义和使用分析的结果,将所述本机接口函数调用的列表的一部分转换为常数、内部即时编译器操作、和更简单的中间表示中的一个。
11.根据权利要求10的数据处理系统,其中所述形状列表包括所述多个本机接口函数调用的中间表示,并包括该多个本机函数调用对本机接口环境变量和用户变元的用法。
12.根据权利要求11的数据处理系统,其中所述即时编译器内嵌器在内嵌本机函数调用期间、响应于检测到内嵌的本机函数调用中的本机接口函数调用而识别用于转换的所述本机接口函数调用列表,且其中该即时编译器内嵌器还执行以下操作对于所述识别的本机接口函数调用列表中的每一个,确定所述本机接口环境变量是否是以在所述生成的形状的列表中的一形状中的相同方式被使用的;如果所述本机接口环境变量是以在所述生成的形状的列表中的一形状中的相同方式被使用的,则确定在该形状和该本机接口函数调用的中间表示之间是否存在匹配,其中如果该本机接口函数调用的中间表示与该形状相比具有相同数量的变元,且该本机接口函数调用中的每个变元与该形状中的变元的类型一致,则存在匹配;以及如果在该形状和该本机接口函数调用的中间表示之间存在匹配,则将该本机接口函数调用添加到所述本机接口函数调用列表,其中该本机接口函数调用列表是按照在所述多个本机接口函数调用的中间表示中出现的顺序排序的。
13.根据权利要求12的数据处理系统,其中所述即时编译器内嵌器在识别了所述本机接口函数调用列表之后跟踪被传递给该本机接口函数调用列表的多个对象到该多个对象作为变元被传递给本机接口函数的位置。
14.根据权利要求13的数据处理系统,其中所述即时调用转换器还执行以下操作对于所述本机接口函数调用列表中的每个本机接口函数调用,确定所述定义和使用分析是否返回已知的结果;如果该定义和使用分析返回已知的结果,则确定该本机接口函数调用的类型;以及根据该本机接口函数调用的类型,将该本机接口函数调用替换为常数值、内部即时编译器操作、和更简单的中间表示中的一个。
15.根据权利要求14的数据处理系统,其中所述即时调用转换器还执行以下操作如果该定义和使用分析返回未知的结果,则从所述本机接口调用列表中丢弃该本机接口函数调用和使用该本机接口函数调用的任何其他本机接口函数调用。
16.根据权利要求14的数据处理系统,其中所述内部即时编译器操作提供了对虚拟机的服务和数据的直接的和更快的访问,其中所述内部即时编译器操作执行其功能而不使用本机接口。
17.一种在计算机可读存储介质中的用于在即时编译期间将本机接口函数调用转换为更简单的操作的计算机程序产品,该计算机程序产品包括用于执行前述方法权利要求的任何方法的指令。
全文摘要
提供了用于将Java本机接口函数调用转换为常数、内部即时编译器操作或更简单的中间表示的方法和系统。编译器生成用于多个本机接口函数调用的多个中间表示。在内嵌本机代码期间,对每个本机函数调用执行匹配(针对该列表),并生成本机接口函数调用的列表。对于每个本机接口函数调用,JIT调用转换器尝试根据该本机接口函数调用的类型将该本机接口函数调用替换为常数、内部即时编译器操作或更简单的中间表示。
文档编号G06F9/45GK1848088SQ20061000825
公开日2006年10月18日 申请日期2006年2月16日 优先权日2005年2月18日
发明者A·H·基尔斯特拉, L·S·斯特帕尼安, K·A·斯图德雷 申请人:国际商业机器公司