1.本发明涉及代码编译领域,尤其涉及一种代码链接优化方法。
背景技术:2.基于符号的代码链接(symbol-based linking)被广泛应用于各种编程语言中,java虚拟机(jvm)中也采用了此项技术,用于方法调用、数据域(field)访问以及其他操作。基于jvm的java card虚拟机(jcvm)因其运行在资源受限的智能卡上,对jvm中原有的代码链接方法进行优化,在代码转换时使用一种特殊的符号,即基于整数的令牌(token),作为java代码中类(class)、方法(method)和域(field)的标识,从而移除在代码链接和代码运行过程中对常量池(constant pool)的依赖和符号解析,最终既减少程序所需安装空间又减少程序运行时间。但作为代价,jcvm为满足向后兼容性,对api的后续修改施加更为严格的限制,比如不能在一个外部可见类或接口中添加新的方法。
3.基于符号的代码链接,其核心内容是符号分配和符号解析,前者影响编译速度,后者影响运行效率。同时为满足符号在一定范围(scope)内具有唯一性的要求,符号的长度都会比较长。对于智能卡等资源受限的嵌入式设备,因为程序大多是在台式机上编译,然后再下载到智能卡上,所以符号解析的影响更大。符号解析的主要工作就是通过比较符号获得被引用类、方法或域的地址。符号越长,比较就越耗时,进而导致指令的执行时间也相应变长。
技术实现要素:4.本发明的目的是提供一种代码链接优化方法,旨在通过在程序安装过程中将符号转换成一个索引(比如1字节整数或其他可以快速比较的数据类型),并在指令执行过程中通过比较该索引,而不是原来比较长的符号来减少符号解析的时间,进而减少指令的执行时间。
5.第一方面,提供了一种代码链接优化方法,包括:
6.获取程序的安装文件,所述安装文件中包含至少一个类;
7.将安装文件安装到目标设备上,得到程序镜像,其中,对于安装文件中类的每个实例域,分配一个唯一的索引;对于安装文件中类的每个虚方法,如果其重写了祖先类中的虚方法,则使用祖先类中的虚方法的索引作为该虚方法的索引,否则,为其分配一个新的索引。
8.在一种可能的实施方式中,所述索引为整数。
9.在一种可能的实施方式中,所述将安装文件安装到目标设备上,得到程序镜像,还包括:
10.对于每个引用实例域的指令,使用分配给它的索引替换指令中原有的操作数;对于每个调用虚方法的指令,使用分配给它的索引替换指令中原有的操作数。
11.在一种可能的实施方式中,所述程序镜像包括第一数据结构和第二数据结构,所
述第一数据结构用于保存为所述实例域分配的索引,所述第二数据结构用于保存为所述虚方法分配的索引。
12.在一种可能的实施方式中,所述获取程序的安装文件,包括:
13.获取程序的源代码,将源代码进行编译和转换,得到程序的安装文件,其中,将程序的类、方法和域的符号保存到安装文件中,其中,所述域包括实例域,所述方法包括虚方法。
14.在一种可能的实施方式中,所述安装文件包括第三数据结构和第四数据结构,所述第三数据结构用于保存所述域的符号,所述第四数据结构用于保存所述方法的符号。
15.在一种可能的实施方式中,所述实例域的索引与实例域的符号一一对应;所述虚方法的索引与虚方法的符号一一对应。
16.在一种可能的实施方式中,在将安装文件安装到目标设备上,得到程序镜像之后,所述方法还包括:
17.运行程序,对于访问实例域的指令,使用操作数中的索引直接访问对应的实例域;对于调用虚方法的指令,使用操作数中的索引和类的元数据中的虚方法表进行比较,获得实际调用虚方法的地址,并调用该虚方法。
18.本发明提出的一种代码链接优化方法,通过在程序安装过程中将符号转换成一个索引,并在指令执行过程中通过比较该索引,而不是原来比较长的符号来减少符号解析的时间,进而减少指令的执行时间。同jcvm中采用的基于令牌的代码链接相比,虽然本发明需要更多的安装空间用来保存符号和符号与索引之间的映射关系,但因为在安装过程中仍使用符号进行链接,所以拥有更宽松的兼容性要求,在后续使用过程中更容易修改api来满足不断变化的需求。而且随着芯片制造技术的不断发展,片上存储的容量不断提升,需要更多安装空间的这一短处几乎可以忽略。
附图说明
19.图1为本发明实施例公开的程序执行的流程示意图;
20.图2为本发明实施例公开的一种代码链接优化方法的流程图;
21.图3为本发明实施例公开的一种接口的转换和链接的代码的示意图;
22.图4为本发明实施例公开的一种类的转换和链接的代码的示意图;
23.图5为本发明实施例公开的一种对虚函数调用指令和实例域访问指令的转换的代码的示意图;
24.图6为本发明实施例公开的一种对虚函数调用指令和域访问指令引进行链接的代码的示意图;
25.图7为本发明实施例公开的一种添加虚方法后并不影响程序的兼容性的代码的示意图。
具体实施方式
26.为使本发明实施例的目的、技术方案和优点更加清楚,下面将结合本发明实施例中的附图,对本发明实施例中的技术方案进行清楚、完整地描述,显然,所描述的实施例是本发明一部分实施例,而不是全部的实施例。基于本发明中的实施例,本领域普通技术人员
在没有做出创造性劳动前提下所获得的所有其他实施例,都属于本发明保护的范围。
27.为便于对本发明实施例的理解,下面将结合附图以具体实施例做进一步的解释说明,实施例并不构成对本发明实施例的限定。
28.图1为本发明实施例公开的程序执行的流程示意图。
29.如图1所示,当前源程序经过编译和转换操作,得到安装文件;安装文件经过安装和链接操作,安装到设备上,得到程序镜像;运行程序镜像中的程序。
30.图2为本发明实施例公开的一种代码链接优化方法的流程图。
31.在步骤s202,获取程序的安装文件,所述安装文件中包含至少一个类,每个类里包含零个或多个实例域(instance field),以及包含零个或多个虚方法(virtual method)或虚函数。
32.可以理解,方法和函数为实质相同的概念,代表一段具有输入和输出的相对独立的子程序,区别仅在于在不同的编程语言中使用的名称不同。例如,在c语言中称为函数,在java语言中则称为方法。为便于表述,以下涉及到方法或函数的表述中,统一使用方法一词。
33.在步骤s203,将安装文件安装到目标设备上,得到程序镜像,其中,对于安装文件中类的每个实例域,分配一个唯一的索引;对于安装文件中类的每个虚方法,如果其重写(override)了祖先类中的虚方法,则使用祖先类中的虚方法的索引作为该虚方法的索引,否则,为其分配一个新的索引。
34.在一些可能的实施方式中,程序的安装,代表将转换时生成的安装文件下载到智能卡等设备上。
35.在一些可能的实施方式中,索引为整数,用于进行快速比较。
36.在一些可能的实施方式中,步骤s203还包括:对于每个引用实例域的指令,使用分配给它的索引替换指令中原有的操作数;对于每个调用虚方法的指令,使用分配给它的索引替换指令中原有的操作数。
37.在一些可能的实施方式中,程序镜像还包括第一数据结构和第二数据结构,所述第一数据结构用于保存为所述实例域分配的索引,所述第二数据结构用于保存为所述虚方法分配的索引。
38.在一些可能的实施方式中,在步骤s202之前还存在步骤s201:获取程序的源代码,将源代码进行编译和转换,得到程序的安装文件,其中,将程序的类、方法和域的符号保存到安装文件中,其中,所述域包括实例域,所述方法包括虚方法。
39.进一步地,所述安装文件包括第三数据结构和第四数据结构,所述第三数据结构用于保存所述域的符号,所述第四数据结构用于保存所述方法的符号。
40.进一步地,所述实例域的索引与实例域的符号一一对应;所述虚方法的索引与虚方法的符号一一对应。
41.在一些可能的实施方式中,在步骤s203之后还存在步骤s204:运行程序,对于访问实例域的指令,使用操作数中的索引直接访问对应的实例域;对于调用虚方法的指令,使用操作数中的索引和类的元数据(class metadata)中的虚方法表进行比较,获得实际调用虚方法的地址,并调用该虚方法。
42.在一些可能的实施方式中,所述访问实例域的指令,可以包括getfield、
putfield;所述访问虚方法的指令,可以包括invokevirtual、invokeinterface。
43.在一个具体的实施例中,使用本发明中的方法对java程序进行代码的链接,具体如图3至图7所示。可以理解,本发明的方法同样也适用于其它面向对象的编程语言,例如c++、c#;本实施例中使用的类名、方法原型和域原型作为符号,但在其他实施例中也可以使用其他数据作为符号;本实施例中使用整形(int)作为方法和域的索引,但在其他实施例中可以使用其他数据作为索引;图3至图7中只包含了与本发明相关的信息和数据结构,其他无关信息都已省略(使用“//......”代替);method_indexes、field_indexes、export_info等数据结构,可以像实施例中那样在生成程序镜像时添加,也可在安装文件中添加,然后在安装时进行初始化。
44.图3为本发明实施例公开的一种接口的转换和链接的代码的示意图。在包package1中,有一个公共访问权限的接口i,接口中有一个虚方法func_i1()。
45.在转换后得到的安装文件中,每个接口都会生成一个interface_info数据结构,其中method_symbols记录每个方法的符号。虚方法func_i1()对应的符号为func_i1()v。
46.在程序安装和链接过程中,会在程序镜像中添加一个数据结构method_indexes,其中保存为每个方法分配的索引。虚方法func_i1()的索引为0。method_indexes中的索引和method_symbols中的符号为一一对应的关系。同时因为接口i是外部可见的,所以将其符号和interface_info对应的地址添加到export_info中,从而在安装其他引用i的接口或类时能够通过i的符号访问interface_info并获取链接所需的信息。接口i的符号为package1.i,地址为0x1010。
47.图4为本发明实施例公开的一种类的转换和链接的代码的示意图。在包package2中,有一个实现了接口i的类a,类a中有两个新定义的虚方法func1()和func2(),同时重写了接口i中的虚方法func_i1(),还有一个新定义的int类型的实例域fielda。
48.在转换后的安装文件中,每个类都会生成一个class_info数据结构。其中的第三数据结构declared_field_symbols只保存当前类中新定义的域的符号,即不包含父类中定义的域,第四数据结构virtual_method_symbols保存当前类中新定义和重写的方法的符号。如图4所示,第三数据结构declared_field_symbols保存了实例域fielda的符号,第四数据结构virtual_method_symbols保存了当前类中新定义和重写的方法的符号func1()v、func2()v和func_i1()v。
49.在安装和链接后生成的程序镜像中,为每个新定义的域分配一个索引并保存在第一数据结构declared_field_indexes中。如果父类中域的总数为n,则新索引从n+1开始;如果父类中没有定义过域,则新索引从0开始。如图4所示,实例域fielda的索引为0,保存在第一数据结构declared_field_indexes中。
50.对于每个虚方法,如果其是对祖先类中某个虚方法的重写,则使用其在祖先类中的索引,否则为其分配一个新的索引。如果父类中虚方法的总数为m,则新索引从m+1开始分配;如果父类中没有虚方法,则新索引从0开始。如图4所示,类a并没有继承任何类,于是func1()v、func2()v、func_i1()v的索引分别是0、1、2,保存在第二数据结构virtual_method_indexes中。同时,祖先接口i中的虚方法func_i1()对应的索引2保存在interfacemethodmap的method_index_map中。
51.同接口一样,对于外部可见的类,也要将其符号和class_info的地址添加在
export_info中,用于安装和链接引用了当前类的其他类。此外在安装过程中还需要将保存在virtual_method_addresses中每个虚方法的逻辑地址替换为真实的物理地址。
52.图5为本发明实施例公开的一种对虚函数调用指令和实例域访问指令的转换的代码的示意图。在包package3中,声明了一个类b,类b中有一个方法foo(),在foo()中,首先声明并初始化了类a的一个对象a1,然后调用了a1中的虚函数func2(),然后使a1中的实例域fielda自增1。
53.在转换后的安装文件中,虚函数调用指令和域访问指令需要通过常量池间接指向要访问的虚方法和域,因此在常量池中需要保存虚方法和域的符号,即类符号+虚方法/域符号,指令操作数中保存被调用方法或被访问域在常量池中的索引。
54.如图5所示,代码a1.func2()对应指令aload_1和invokevirtual 0,其中0即为常量池索引,而常量池中表项0即对应类package2.a中的虚方法func2。含有实例域访问的代码a1.fielda+=1对应后6条指令,其中对域的访问也采用相同的方法。指令getfield_s 1和putfield_s 1中的操作数1也是常量池索引,其指向的常量池表项对应package2.a中的域fielda。
55.图6为本发明实施例公开的一种对虚函数调用指令和域访问指令引进行链接的代码的示意图。步骤1-3为虚函数链接的过程,步骤4-6为实例域链接的过程。
56.对于虚函数链接,第1步,使用类的符号package2.a在package2程序镜像的export_info中获得类a的class_info的地址0x2020。第2步,在类a的class_info的第四数据结构virtual_method_symbols中查找虚方法符号“func2()v”,并获得其位置,然后使用该位置从第二数据结构virtual_method_indexes中获得“func2()v”的方法索引1。第3步,用方法索引1替换package3程序镜像中虚方法调用指令invokevirtual中的操作数0,得到invokevirtual 1。
57.对于实例域链接,第4步,使用类的符号“package2.a”在package2程序镜像的export_info中获得类a的class_info的地址。第5步,在类a的class_info的第三数据结构declared_field_symbols中查找域符号“fielda”,并获得其位置,然后使用该位置从第一数据结构declared_field_indexes中获得“fielda”的域索引0。第6步,用域索引0替换package3程序镜像中域访问指令getfield_s,putfield_s中的操作数1,得到getfield_s 0和putfield_s 0。
58.图7为本发明实施例公开的一种添加虚方法后并不影响程序的兼容性的代码的示意图。如图7所示,假设当前设备上安装的是新版的类a,其中添加了一个新的虚方法func3,如代码块(a)所示,相应地package2程序镜像中a所对应的class_info,func2对应的方法索引由1变成了2,如代码块(b)所示。此时在设备上安装使用旧版本类a编译的类b时,如代码块(c)所示,仍然可以通过符号“package2.a.func2()v”链接到正确的方法上,invokevirtual指令中的操作数也变成了func2的新索引2,如代码块(e)所示。由此可见,添加新的虚方法后并不影响程序的兼容性。
59.以上所述的具体实施方式,对本发明的目的、技术方案和有益效果进行了进一步详细说明,所应理解的是,以上所述仅为本发明的具体实施方式而已,并不用于限定本发明的保护范围,凡在本发明的精神和原则之内,所做的任何修改、等同替换、改进等,均应包含在本发明的保护范围之内。