针对动态语言的处理及优化方法、装置、设备及存储介质
技术领域
本公开涉及编程领域,特别是涉及一种针对动态语言的处理及优化方法、装置、设备及存储介质。
背景技术
静态语言(也即静态类型语言)是在编译时变量的数据类型即可确定的语言,多数静态类型语言要求在使用变量之前必须声明数据类型。例如,C++、Java、Delphi、C#等都是静态语言。
与静态语言不同,动态语言(也即动态类型语言)是在运行时确定数据类型的语言,变量使用之前不需要类型声明,通常变量的类型是被赋值的那个值的类型。例如,PHP、ASP、Ruby、Python、Perl、ABAP、SQL、JavaScript、Unix Shell等都是动态语言。
对于动态语言而言,类型判断、对象的内存分配等一系列操作一般是在运行期间执行的,使得基于动态语言编写的程度的运行性能较慢,降低用户的使用体验。
因此,需要一种能够对基于动态语言编写的程序进行优化的方案。
发明内容
本公开的一个目的在于提供一种能够对基于动态语言编写的程序进行优化的方案。
根据本公开的第一个方面,提供了一种针对动态语言的优化方法,用于对基于动态语言编写的源文件进行优化,包括:基于源文件获得带有标注信息的中间文件,标注信息用于标注源文件中的至少部分程序代码的数据类型;基于中间文件中的程序代码进行分析得到抽象语法树,其中,对标注信息进行分析得到相应程序代码的类型描述信息,并且将类型描述信息附加到抽象语法树上相应程序代码对应的节点上;遍历抽象语法树,以基于节点间的关联关系以及节点的类型描述信息,得到类构造的对象所拥有的属性及类型信息,根据属性及类型信息生成隐藏类,并将隐藏类附加到该对象所对应的类定义节点上;基于抽象语法树以及类定义节点上的隐藏类,生成优化代码。
可选地,类型描述信息包括以下一项或多项:基本类型;对象类型;函数类型;布尔类型;无类型。
可选地,基于源文件获得带有标注信息的中间文件的步骤包括:对源文件中至少部分程序代码的数据类型进行标注,以得到中间文件。
可选地,源文件是经过第一类型***标注得到的,基于源文件获得带有标注信息的中间文件的步骤包括:将源文件中的标注信息转换为对应于第二类型***的标注信息,并保留源文件中的程序代码本身的语义,以得到中间文件。
可选地,第一类型***是TypeScript或Flow.js,并且/或者第二类型***支持基本类型、对象类型、函数类型、布尔类型以及无类型。
可选地,第二类型***中对象类型、函数类型以及数组类型之间不可相互转化,并且/或者,第二类型***中数组类型的索引为标量类型。
可选地,对于抽象语法树中对应于同一类的节点,遍历该类的所有节点,根据节点的类型描述信息,得到该类所构造的对象所拥有的属性及类型信息,根据属性及类型信息,生成该类的隐藏类。
可选地,生成优化代码的步骤包括:遍历抽象语法树,为每个节点生成代码。
可选地,对于抽象语法树中具有隐藏类的第一节点,将该第一节点翻译为能够利用隐藏类执行的第一代码,并且/或者对于抽象语法树中不具有隐藏类的第二节点,将该第二节点翻译为在运行时获取隐藏类并基于获取的隐藏类执行的第二代码。
可选地,在第一节点为分配对象的情况下,将该第一节点翻译为根据第一节点的隐藏类确定对象的线性布局区域大小并分配对象的第一代码。
可选地,在第一节点为访问对象属性的情况下,还生成用于判断第一节点自带的隐藏类与生成的隐藏类是否一致且自带的隐藏类与生成的隐藏类是否具有继承关系的判断代码,并且/或者在第一节点自带的隐藏类与生成的隐藏类不一致,且自带的隐藏类与生成的隐藏类具有继承关系的情况下,将该第一节点翻译为能够利用隐藏类执行的第一代码。
根据本公开的第二个方面,还提供了一种针对动态语言的处理方法,用于对基于动态语言编写的源文件进行处理,包括:基于源文件获得带有标注信息的中间文件,标注信息用于标注源文件中的至少部分程序代码的数据类型;基于中间文件中的程序代码进行分析得到抽象语法树,其中,对标注信息进行分析得到相应程序代码的类型描述信息,并且将类型描述信息附加到抽象语法树上相应程序代码对应的节点上;以及遍历抽象语法树,以基于节点间的关联关系以及节点的类型描述信息,得到类构造的对象所拥有的属性及类型信息,根据属性及类型信息生成隐藏类,并将隐藏类附加到该对象所对应的类定义节点上。
根据本公开的第三个方面,还提供了一种针对动态语言的优化装置,用于对基于动态语言编写的源文件进行优化,包括:中间文件获取单元,用于基于源文件获得带有标注信息的中间文件,标注信息用于标注源文件中的至少部分程序代码的数据类型;行分析得到抽象语法树,其中,对标注信息进行分析得到相应程序代码的类型描述信息,并且将类型描述信息附加到抽象语法树上相应程序代码对应的节点上;隐藏类生成单元,用于遍历抽象语法树,以基于节点间的关联关系以及节点的类型描述信息,得到类构造的对象所拥有的属性及类型信息,根据属性及类型信息生成隐藏类,并将隐藏类附加到该对象所对应的类定义节点上;优化代码生成单元,用于基于抽象语法树以及类定义节点上的隐藏类,生成优化代码。
可选地,类型描述信息包括以下一项或多项:基本类型;对象类型;函数类型;布尔类型;无类型。
可选地,中间文件获取单元对源文件中至少部分程序代码的数据类型进行标注,以得到中间文件。
可选地,源文件是经过第一类型***标注得到的,中间文件获取单元将源文件中的标注信息转换为对应于第二类型***的标注信息,并保留源文件中的程序代码本身的语义,以得到中间文件。
可选地,第一类型***是TypeScript或Flow.js,并且/或者第二类型***支持基本类型、对象类型、函数类型、布尔类型以及无类型。
可选地,第二类型***不支持对象类型、函数类型以及数组类型之间相互转化,并且/或者,第二类型***中数组类型的索引为标量类型。
可选地,对于抽象语法树中对应于同一类的节点,隐藏类生成单元遍历该类的所有节点,根据节点的类型描述信息,得到该类所构造的对象所拥有的属性及类型信息,根据属性及类型信息,生成该类的隐藏类。
可选地,优化代码生成单元遍历抽象语法树,为每个节点生成代码。
可选地,对于抽象语法树中具有隐藏类的第一节点,优化代码生成单元将该第一节点翻译为能够利用隐藏类执行的第一代码,并且/或者对于抽象语法树中不具有隐藏类的第二节点,优化代码生成单元将该第二节点翻译为在运行时获取隐藏类并基于获取的隐藏类执行的第二代码。
可选地,在第一节点为分配对象的情况下,优化代码生成单元该第一节点翻译为根据第一节点的隐藏类确定对象的线性布局区域大小并分配对象的第一代码。
可选地,在第一节点为访问对象属性的情况下,优化代码生成单元还生成用于判断第一节点自带的隐藏类与生成的隐藏类是否一致且自带的隐藏类与生成的隐藏类是否具有继承关系的判断代码,并且/或者在第一节点自带的隐藏类与生成的隐藏类不一致,且自带的隐藏类与生成的隐藏类具有继承关系的情况下,优化代码生成单元将该第一节点翻译为能够利用隐藏类执行的第一代码。
根据本公开的第四个方面,还提供了一种针对动态语言的处理装置,用于对基于动态语言编写的源文件进行处理,包括:中间文件获取单元,用于基于源文件获得带有标注信息的中间文件,标注信息用于标注源文件中的至少部分程序代码的数据类型;分析单元,用于基于中间文件中的程序代码进行分析得到抽象语法树,其中,对标注信息进行分析得到相应程序代码的类型描述信息,并且将类型描述信息附加到抽象语法树上相应程序代码对应的节点上;以及隐藏类生成单元,用于遍历抽象语法树,以基于节点间的关联关系以及节点的类型描述信息,得到类构造的对象所拥有的属性及类型信息,根据属性及类型信息生成隐藏类,并将隐藏类附加到该对象所对应的类定义节点上。
根据本公开的第五个方面,还提供了一种计算设备,包括:处理器;以及存储器,其上存储有可执行代码,当可执行代码被处理器执行时,使处理器执行如本公开第一个方面或第二个方面述及的方法。
根据本公开的第六个方面,还提供了一种非暂时性机器可读存储介质,其上存储有可执行代码,当可执行代码被电子设备的处理器执行时,使处理器执行如本公开第一个方面或第二个方面述及的方法。
综上,本公开通过在编译时预生成隐藏类,由此可以提前知道对象布局信息,从而可以基于预生成的隐藏类,对源文件进行优化以避免运行时添加属性创建隐藏类和扩展对象布局的开销,提高运行速率。
附图说明
通过结合附图对本公开示例性实施方式进行更详细的描述,本公开的上述以及其它目的、特征和优势将变得更加明显,其中,在本公开示例性实施方式中,相同的参考标号通常代表相同部件。
图1示出了本公开的TA类型***与现有的两种标注***的区别示意图。
图2示出了根据本公开一实施例的针对动态语言的优化方法的示意性流程图。
图3示出了将AST翻译为代码的示意性流程图。
图4示出了基于隐藏类生成优化代码的示意性流程图。
图5示出了根据本公开一实施例的针对动态语言的优化装置的结构的示意性方框图。
图6示出了根据本公开一实施例的针对动态语言的处理装置的结构示意图。
图7示出了根据本公开一实施例的计算设备的结构的示意性方框图。
具体实施方式
下面将参照附图更详细地描述本公开的优选实施方式。虽然附图中显示了本公开的优选实施方式,然而应该理解,可以以各种形式实现本公开而不应被这里阐述的实施方式所限制。相反,提供这些实施方式是为了使本公开更加透彻和完整,并且能够将本公开的范围完整地传达给本领域的技术人员。
【术语解析】
首先,就本公开涉及的术语做简要说明。
JavaScript,用于网页编程的动态语言。
JS,JavaScript语言的简称。
JS虚拟机,JavaScript语言执行引擎,用于编译和运行JavaScript源码。
TypeScript,微软开发的兼容编程语言。
Int,整数类型。
Float,单精度浮点类型。
Double,双精度浮点类型。
Boolean,布尔类型。
Native App,传统的移动端的应用程序,一般不跨平台、终端,要下载安装。
隐藏类,又称为Hidden-Class,也可称为为map或者shape,用来描述动态语言的动态对象布局的一种数据结构设计。
对象布局,对象内存布局的简称,指对象各个属性在对象指针所指向的内存区域中的排布。
Native Code,机器指令。
IC,一种编译优化技术Inline Cache的简称。
IC-HIT,已生成的隐藏类可以描述当前对象布局。
IC-MISS,当已生成的隐藏类不能描述当前对象布局时,需要重新对对象属性进行生成。
IC-SLOW-PATH,当前隐藏类和已生成的隐藏类不一致时,需要对对象属性进行查询,得到属性的内存位置信息,并重新生成隐藏类来描述当前对象布局。
IC-FAST-PATH,当前对象的隐藏类和已生成的隐藏类一致,说明已生成的隐藏类可以描述当前对象布局,对对象的读写操作可以快速完成。
JIT,运行时编译器just in time技术的简称。
Object-C,苹果公司发明的编程语言。
Java,Sun公司发明的一种强类型通用编程语言。
OOP,Object Oriented Programming,面向对象编程的简称。
AST,Abstract Syntax Tree,抽象语法树的简称。
In-Object区域,当对象属性的个数少于某个预先指定数目(用MAX_L表示)时,采用线性布局,即属性值依次排布,同时存在于对指针所指向的内存区域。
Out-Object区域,指与In-Object区域相对的概念,即不再In-Object之内,便属于Out-Object区域。
【方案概述】
为了提高基于动态语言编写的源文件的运行效率,本公开提出,可以在编译时预生成隐藏类,由此可以提前知道对象布局信息,从而可以基于预生成的隐藏类,对源文件进行优化以避免运行时添加属性创建隐藏类和/或扩展对象布局的开销,提高运行速率。例如,可以生成IC-FAST-PATH来加速运行效率。
举例来说,由于本公开是在编译时已经预先生成了对象的隐藏类,因此可以知道该对象所拥有的所有属性以及属性的类型信息,那么就可以生成根据预生成的隐藏类确定对象的In-Object区域大小并为对象分配内存区域的优化代码。因为所有的属性都已经在预生成的隐藏类中描述好了,因此在运行时无论何时添加新的属性,都不会发生In-Object区域容纳不下的问题。并且,在运行时添加新的属性时,并不需要生成新的隐藏类,因为隐藏类在编译时已经预先得到了。
进一步地,为了实现隐藏类的预生成,本公开还提出了一种新的标注方案(可以称为“TA类型***”)。TA类型***从设计上提高了标量类型的分类,减少了不必要的类型之间的转换,使得采用TA类型***的动态语言有能力开发***级别的应用程序。
下面主要以JavaScript为例,就本公开涉及的各种方面做详细说明。应该知道,本公开也可以适用于其它多种类型的动态语言,并且在应用于其它动态语言时,也可以根据具体编程语言的实现机理做适应性改变,此处不再赘述。
【TA类型***】
图1示出了本公开的TA类型***与现有的两种标注***的区别示意图。
本公开的TA类型***可以支持基本类型、对象类型、函数类型、布尔类型以及无类型等多种类型的标注。如图1所示,与TypeScrip和Flow.js不同,TA类型***可以支持整型标量int、整型标量long、浮点类型标量float、浮点类型标量double等标量类型的标注。
由此,基于TA类型***进行标注得到的标注信息(可以称为“TA标注信息”),可以确定对象所拥有的所有属性的类型,从而为隐藏类的预生成提供实现基础。
进一步地,为了减少不必要的类型之间的转换,本公开的TA类型***不支持对象类型、函数类型以及数组类型之间的相互转化。并且,数组类型的索引只能使标量int、标量long。如此,可以在一定程度上简化TA类型***。
关于使用TA类型***对源文件中的程序代码进行标注的实现过程,与现有的类型***相似,如可以参见TypeScrip和Flow.js,本公开不再赘述。
【隐藏类的预生成】
图2示出了根据本公开一实施例的优化方法的示意性流程图。
参见图2,首先在步骤S110,获得源文件。
步骤S110中述及的源文件是指基于动态语言编写的程序文件。其中,此处述及的动态语言可以是JavaScript、PHP、ASP、Ruby、Python、Perl、ABAP、SQL、Unix Shell等动态语言,也可以是对这些动态语言进行标注的扩展语言,如可以是TypeScrip、Flow.js等基于JavaScript扩展的提供了类型标注功能的动态语言。
与JavaScript不同,基于TypeScrip、Flow.js编写的源文件中不仅具有JS代码,还包括对JS代码的数据类型进行标注的标注信息。其中,TypeScrip、Flow.js为本领域现有技术,此处不再赘述。
在步骤S120,基于源文件得到中间文件。
对于没有利用类型***进行标注过的源文件,可以使用本公开的TA类型***对源文件中的至少部分程序代码的数据类型进行标注,以得到带有TA标注信息的中间文件。
对于利用现有的类型***(可以称为“第一类型***”)进行标注过的源文件,如基于TypeScrip、Flow.js等类型***标注得到的带有标注信息的源文件,可以对该源文件进行转换,将其中的标注信息转换为对应TA类型***(可以称为“第二类型***”)的TA标注信息,并保留代码本身的语义。也就是说,此处述及的转换,主要是集中在类型***的翻译,即把源文件中的标注信息转换为对应于第二类型***的TA标注信息,并保留其中的程序代码本身的语义,即保留非标注部分的原始程序代码的语义。
在步骤S130,得到附加类型描述信息的抽象语法树(AST)。
在得到带有TA标注信息的JS代码(即中间文件)后,可以对中间文件进行语法分析,如可以对中间文件中的程序代码进行分析得到AST,对TA标注信息进行分析得到相应程序代码的类型描述信息,并且将类型描述信息附加到AST上相应程序代码对应的节点上。
对中间文件进行语法分析的过程和现有的JS虚拟机对JS代码进行的语法分析的过程大体相同。不同之处在于,中间文件不是标准的JS代码,而是带有TA标注信息的JS代码,因此在进行语法分析时候,需要对其中的TA标注信息进行另外的分析。对TA标注信息进行分析得到的结果(即类型描述信息)可以是基本类型、对象类型、函数类型、布尔类型、无类型共5种可能的类型。为了便于描述,本公开以TA-DES(类型描述信息,也可称为“类型描述符”)来表示TA标注信息的分析结果。在分析完TA标注信息生成TA-DES之后,TA-DES要附加到对应的AST节点上,供后续步骤查询之用。
在步骤S140,遍历AST并分析类型描述信息,生成隐藏类。
JavaScript中的所有事物都是对象,并且JavaScript允许自定义类来构造同一对象。AST中的每个节点可以表征JS代码的一个语法结构,类(class)所定义的属性和类型可以根据AST节点上附加的TA-DES确定。因此,可以基于节点间的关联关系以及节点的TA-DES,得到类所定义的所有属性及类型信息,根据类型信息生成隐藏类,并将隐藏类附加到该类所对应的节点(即类定义节点)上。其中,类定义节点可以视为该类的继承链的最上层节点,类定义节点上附加的隐藏类可以用于描述该类的继承链中所有子类对象的布局信息。由此,可以为避免OOP编程的多继承导致的IC-MISS发生提供实现基础(具体见下文描述)。
也就是说,对于AST中对应于同一类(class)的节点,可以遍历该类的继承链上的所有节点,根据节点的类型描述信息,得到该类所构造的对象所拥有的属性及类型信息,根据属性及类型信息,生成该类的隐藏类。
具体而言,对于class类型的AST节点,要分析其所绑定的TA-DES,如果没有TA-DES则跳过该AST节点。如果有TA-DES信息,那么则要沿着该class的继承链一直往上分析,即遍历class的所有父类AST节点,如果父类AST节点有TA-DES信息,则进行收集。这样最终得到该class所构造的对象所拥有的所有属性信息以及属性的类型。最后根据这些信息为该class生成隐藏类并附加到class类型对应的AST节点(即类定义节点)上。
需要说明的是,本公开是在遍历AST的过程中便已经生成隐藏类,而不像传统的IC优化方法是在运行时添加属性时才能生成隐藏类,这是区别于业界常用的IC优化方法的重要一点。
最后在步骤S150,根据上一步生成的带有隐藏类的AST来生成高效的优化代码,此处述及的优化代码可以是字节码(bytecode),也可以是机器码(native code),对此本公开并无特别指定。具体生成高效的优化代码流程(即步骤S150)将在图3中进行说明。
【优化代码的生成】
图3示出了基于隐藏类生成优化代码的示意性流程图。
输入是节点带有隐藏类的AST,可以深度递归遍历AST,为每个节点生成优化代码。本公开用IC-SLOW-PATH和IC-FAST-PATH来泛指慢速路径和快速路径,慢速路径是指运行时发生了预生成的隐藏类和运行时遇到的对象不一致,那么需要生成新的隐藏类来描述当前对象布局,并且如果是对对象属性的读写访问,还必须先查询新生成的隐藏类来获取要访问的属性在对象布局中的索引,进而得到其所在的内存位置信息才能进行访问操作。而快速路径是指预生成的隐藏类能够描述运行时出现的对象布局,所以不需要查询隐藏类中要访问的属性在对象布局中的索引。
参见图3,在步骤S210,遍历AST。
在步骤S220,判断当前节点是否为空节点。
如果当前节点为空,则表明遍历完成(即步骤S260),退出。
在判定当前节点不为空节点的情况下,跳至步骤S230,判断当前节点是否附带了预生成的隐藏类。
如果当前节点附带了预生成的隐藏类,则可以执行步骤S240,利用隐藏类信息来翻译成能够利用隐藏类执行的高效的优化代码(可以称为“第一代码”),例如可以翻译成IC-FAST-PATH。
如果没有隐藏类,则可以执行步骤S250,可以和传统的IC优化方法一样,将该第二节点翻译为在运行时获取隐藏类并基于获取的隐藏类执行的非优化代码(可以称为“第二代码”),例如可以翻译成IC-SLOW-PATH,即等到运行时才能收集到类型信息并基于得到的类型信息重新生成IC-FAST-PATH。
具体来说,因为没有任何隐藏类信息,那么该AST节点只能翻译为IC-SLOW-PATH,即如果是对对象属性的读写访问,那么在运行时要先查询对象的隐藏类,得到属性在对象布局中的索引,然后根据索引得到属性的内存位置信息,然后才能访问。如果是添加属性,则需要先检查对象的属性个数是否已经超过了MAX_L,如果超过了,那么该对象要直接转成为字典布局。如果没有超过,那么也要检查In-Obj区域是否能容纳下新增属性,如果可以那么直接添加到In-Obj区域,并生成新的隐藏类。如果In-Obj区域不能容纳,则添加到Out-Obj区域,并生成新的隐藏类。这和业界JS引擎采用的IC-SLOW-PATH方案类似,此处不再赘述。
下面就根据隐藏类生成高效优化代码的过程(即步骤S240)做进一步说明。
参见图4,在步骤S310,分析AST节点类型。此处主要是分析AST节点是否为分配对象或者访问对象属性。对于对非访问对象属性和分配对象的类型的AST节点的代码生成和业界JS引擎类似,本公开不再赘述。
在步骤S320,判断AST节点是否为分配对象,如果是,则转到步骤S330。反之转到步骤S340。
在步骤S330,因为已经预先生成了对象的隐藏类,即可以知道该对象一共有几个属性等信息,那么就可以生成根据预计算的隐藏类来得到对象的In-Obj区域大小来来分配对象In-Obj区域的优化代码。而且在运行时无论何时添加新的属性,都不会发生In-Obj区域容纳不下的问题。因为所有的属性都已经在预计算的隐藏类中描述好了。同时在运行时添加新的属性时,并不需要生成新的隐藏类,因为预计算的隐藏类计算好了。这是区别于业界JS引擎在生成分配对象代码上的重要创新。业界JS引擎因为在生成分配对象代码时并不知道对象有多少属性,于是不能决定In-Obj区域的大小,而本公开则可以。
在步骤S340,判断对象是否为访问对象属性。如果是,则转到步骤S350,反之转到步骤S370。
在步骤370,执行其它处理。对于非访问属性和分配对象的类型的AST节点的代码生成和业界JS引擎类似,故此处不赘述。
在步骤S350,生成判断对象自带的隐藏类和预先计算好的隐藏类是否一致的代码(此处可以称为“判断代码”)。
在业界传统的IC优化技术中是直接比较对象自带的隐藏类和预计算好的隐藏类对象是否一致(比如通过比较指针是否相等的方式)。如果一致则说明预计算的隐藏类可以描述当前对象布局即IC-HIT。否则认为IC-MISS。
但是,在本公开中,判断代码除了比较对象是否一致之外,还要比较两者是否有继承关系(可以通过在生成隐藏类时记录下的其父类对应的隐藏类信息来完成),如果有继承关系,那么尽管两者不一致,但是也不发生IC-MISS。因为通过类型标注,可以保证所有子类对象在其父类中继承的属性在子类和父类对象中的布局(即相对对象指针的偏移位置)都是一样的。这样就避免了OOP编程的多继承导致的IC-MISS发生。当两者隐藏类不相等,同时也没有继承关系时,只能走IC-SLOW-PATH路径。
在步骤S360,因为对象的所有属性的对象布局信息都可以在隐藏类中查询,那么就可以直接得到属性的内存位置信息,并且可以生成直接访问属性的高效代码即IC-FAST-PATH。而这样的代码传统的IC优化方法要在运行时生成新的隐藏类之后才可能生成,这是本公开相对传统IC优化方法的又一个创新区别。
在步骤S380,对AST节点的代码生成过程完成,即回到图3中的步骤S210,遍历AST,继续对下一个AST节点进行处理。
至此,结合图2至图4就本公开的优化方法做了详细说明。另外,本公开还可以实现为一种针对动态语言的处理方法,可以用于对基于动态语言编写的源文件进行处理,以预生成隐藏类。其中,可以通过执行图2中的步骤S110至步骤S150来实现本发明的处理方法,此处不再赘述。
【优化装置】
图5示出了根据本公开一实施例的针对动态语言的优化装置的结构示意图。其中,优化装置500的功能模块可以由实现本发明原理的硬件、软件或硬件和软件的结合来实现。本领域技术人员可以理解的是,图5所描述的功能模块可以组合起来或者划分成子模块,从而实现上述发明的原理。因此,本文的描述可以支持对本文描述的功能模块的任何可能的组合、或者划分、或者更进一步的限定。
下面就优化装置500可以具有的功能模块以及各功能模块可以执行的操作做简要说明,对于其中涉及的细节部分可以参见上文描述,这里不再赘述。
参见图5,优化装置500用于对基于动态语言编写的源文件进行优化。优化装置可以包括中间文件获取单元510、分析单元520、隐藏类生成单元530以及优化代码生成单元540。
中间文件获取单元510用于基于源文件获得带有标注信息的中间文件,标注信息用于标注源文件中的至少部分程序代码的数据类型。此处述及的标注信息是指与TA类型***对应的TA标注信息,其中关于TA类型***所支持的类型及相关内容可以参见上文结合图1的描述。
对于不带标注信息的源文件,中间文件获取单元510可以基于TA类型***对源文件中的至少部分程序代码的数据类型进行标注,以得到带有TA标注信息的中间文件。
对于利用现有的类型***(可以称为“第一类型***”)进行标注过的源文件,如基于TypeScrip、Flow.js等类型***标注得到的带有标注信息的源文件,中间文件获取单元510可以对该源文件进行转换,将其中的标注信息转换为对应第二类型***(即TA类型***)的标注信息(即TA标注信息),并保留源文件中的程序代码本身的语义。
在得到带有TA标注信息的中间文件后,分析单元520可以基于中间文件中的程序代码进行分析得到抽象语法树,对标注信息进行分析得到相应程序代码的类型描述信息,并且将类型描述信息附加到抽象语法树上相应程序代码对应的节点上。其中,对标注信息进行分析得到的类型描述信息可以包括基本类型、对象类型、函数类型、布尔类型、无类型共5种可能的类型。
隐藏类生成单元530用于遍历抽象语法树,以基于节点间的关联关系以及节点的类型描述信息,得到类所构造的对象所拥有的属性及类型信息,根据属性及类型信息生成隐藏类,并将隐藏类附加到该对象所对应的类定义节点上。
例如,对于AST中对应于同一类(class)的节点,隐藏类生成单元530可以遍历该类的所有节点,根据节点的类型描述信息,得到该类所构造的对象所拥有的属性及类型信息,根据属性及类型信息,生成该类的隐藏类。
优化代码生成单元540用于基于抽象语法树以及类定义节点上的隐藏类,生成优化代码。
优化代码生成单元540可以遍历抽象语法树,为每个节点生成代码。其中,对于抽象语法树中具有隐藏类的第一节点,优化代码生成单元540可以将该第一节点翻译为能够利用所述隐藏类执行的第一代码(例如IC-FAST-PATH));对于抽象语法树中不具有隐藏类的第二节点,优化代码生成单元540可以将该第二节点翻译为在运行时获取隐藏类并基于获取的隐藏类执行的第二代码(例如IC-SLOW-PATH)。
具体来说,在第一节点为分配对象的情况下,优化代码生成单元540可以将该第一节点翻译为根据第一节点的隐藏类确定对象的线性布局区域大小并分配对象的第一代码。
在第一节点为访问对象属性的情况下,优化代码生成单元540还可以生成用于判断第一节点自带的隐藏类与生成的隐藏类是否一致且自带的隐藏类与生成的隐藏类是否具有继承关系的判断代码。并且,在第一节点自带的隐藏类与生成的隐藏类不一致,且自带的隐藏类与生成的隐藏类具有继承关系的情况下,优化代码生成单元540可以将该第一节点翻译为能够利用隐藏类执行的第一代码。
【处理装置】
图6示出了根据本公开一实施例的针对动态语言的处理装置的结构示意图。其中,处理装置600的功能模块可以由实现本发明原理的硬件、软件或硬件和软件的结合来实现。本领域技术人员可以理解的是,图5所描述的功能模块可以组合起来或者划分成子模块,从而实现上述发明的原理。因此,本文的描述可以支持对本文描述的功能模块的任何可能的组合、或者划分、或者更进一步的限定。
下面就处理装置600可以具有的功能模块以及各功能模块可以执行的操作做简要说明,对于其中涉及的细节部分可以参见上文描述,这里不再赘述。
参见图6,处理装置600用于对基于动态语言编写的源文件进行处理。优化装置可以包括中间文件获取单元610、分析单元620以及隐藏类生成单元630。
中间文件获取单元610用于基于源文件获得带有标注信息的中间文件,标注信息用于标注源文件中的至少部分程序代码的数据类型;
分析单元620用于基于中间文件中的程序代码进行分析得到抽象语法树,其中,对标注信息进行分析得到相应程序代码的类型描述信息,并且将类型描述信息附加到抽象语法树上相应程序代码对应的节点上;以及
隐藏类生成单元630用于遍历抽象语法树,以基于节点间的关联关系以及节点的类型描述信息,得到类所构造的对象所拥有的属性及类型信息,根据属性及类型信息生成隐藏类,并将隐藏类附加到该对象所对应的类定义节点上。
关于中间文件获取单元610、分析单元620以及隐藏类生成单元630的具体实现功能可以参见上文图5的描述,此处不再赘述。
【计算设备】
图7示出了根据本发明一实施例可用于实现上述针对动态语言的优化方法或处理方法的数据处理的计算设备的结构示意图。
参见图7,计算设备1000包括存储器1010和处理器1020。
处理器1020可以是一个多核的处理器,也可以包含多个处理器。在一些实施例中,处理器1020可以包含一个通用的主处理器以及一个或多个特殊的协处理器,例如图形处理器(GPU)、数字信号处理器(DSP)等等。在一些实施例中,处理器1020可以使用定制的电路实现,例如特定用途集成电路(ASIC,Application Specific Integrated Circuit)或者现场可编程逻辑门阵列(FPGA,Field Programmable Gate Arrays)。
存储器1010可以包括各种类型的存储单元,例如***内存、只读存储器(ROM),和永久存储装置。其中,ROM可以存储处理器1020或者计算机的其他模块需要的静态数据或者指令。永久存储装置可以是可读写的存储装置。永久存储装置可以是即使计算机断电后也不会失去存储的指令和数据的非易失性存储设备。在一些实施方式中,永久性存储装置采用大容量存储装置(例如磁或光盘、闪存)作为永久存储装置。另外一些实施方式中,永久性存储装置可以是可移除的存储设备(例如软盘、光驱)。***内存可以是可读写存储设备或者易失性可读写存储设备,例如动态随机访问内存。***内存可以存储一些或者所有处理器在运行时需要的指令和数据。此外,存储器1010可以包括任意计算机可读存储媒介的组合,包括各种类型的半导体存储芯片(DRAM,SRAM,SDRAM,闪存,可编程只读存储器),磁盘和/或光盘也可以采用。在一些实施方式中,存储器1010可以包括可读和/或写的可移除的存储设备,例如激光唱片(CD)、只读数字多功能光盘(例如DVD-ROM,双层DVD-ROM)、只读蓝光光盘、超密度光盘、闪存卡(例如SD卡、min SD卡、Micro-SD卡等等)、磁性软盘等等。计算机可读存储媒介不包含载波和通过无线或有线传输的瞬间电子信号。
存储器1010上存储有可处理代码,当可处理代码被处理器1020处理时,可以使处理器1020执行上文述及的针对动态语言的优化方法或处理方法。
综上,本公开通过TA类型***,能够在编译时预生成隐藏类,这样就能提前知道对象布局信息,从而避免运行时添加属性创建隐藏类和扩展对象布局的开销,同时能够提前生成IC-FAST-PATH来加速运行效率。最后通过扩展IC机制,即当缓存隐藏类指针和当前对象的隐藏类指针不相等时,通过检查两者是否有继承关系来避免发生IC-MISS从而实现了对OOP多继承编程模型的IC优化。
上文中已经参考附图详细描述了根据本发明的针对动态语言的优化方法、装置以及计算设备。
此外,根据本发明的方法还可以实现为一种计算机程序或计算机程序产品,该计算机程序或计算机程序产品包括用于执行本发明的上述方法中限定的上述各步骤的计算机程序代码指令。
或者,本发明还可以实施为一种非暂时性机器可读存储介质(或计算机可读存储介质、或机器可读存储介质),其上存储有可执行代码(或计算机程序、或计算机指令代码),当所述可执行代码(或计算机程序、或计算机指令代码)被电子设备(或计算设备、服务器等)的处理器执行时,使所述处理器执行根据本发明的上述方法的各个步骤。
本领域技术人员还将明白的是,结合这里的公开所描述的各种示例性逻辑块、模块、电路和算法步骤可以被实现为电子硬件、计算机软件或两者的组合。
附图中的流程图和框图显示了根据本发明的多个实施例的***和方法的可能实现的体系架构、功能和操作。在这点上,流程图或框图中的每个方框可以代表一个模块、程序段或代码的一部分,所述模块、程序段或代码的一部分包含一个或多个用于实现规定的逻辑功能的可执行指令。也应当注意,在有些作为替换的实现中,方框中所标记的功能也可以以不同于附图中所标记的顺序发生。例如,两个连续的方框实际上可以基本并行地执行,它们有时也可以按相反的顺序执行,这依所涉及的功能而定。也要注意的是,框图和/或流程图中的每个方框、以及框图和/或流程图中的方框的组合,可以用执行规定的功能或操作的专用的基于硬件的***来实现,或者可以用专用硬件与计算机指令的组合来实现。
以上已经描述了本发明的各实施例,上述说明是示例性的,并非穷尽性的,并且也不限于所披露的各实施例。在不偏离所说明的各实施例的范围和精神的情况下,对于本技术领域的普通技术人员来说许多修改和变更都是显而易见的。本文中所用术语的选择,旨在最好地解释各实施例的原理、实际应用或对市场中的技术的改进,或者使本技术领域的其它普通技术人员能理解本文披露的各实施例。