平码五不中公式规律
  • / 57
  • 下载费用:30 金币  

处理值类型.pdf

关 键 ?#21097;?/dt>
处理 类型
  专利查询网所有资源均是用户自行上传分享,仅供网友学习交流,未经上传用户书面授权,请勿作他用。
摘要
申请专利号:

CN201580026936.4

申请日:

2015.05.13

公开号:

CN106663019A

公开日:

2017.05.10

当前法律状态:

实审

?#34892;?#24615;:

审中

法?#19978;?#24773;: 实质审查的生效IPC(主分类):G06F 9/45申请日:20150513|||公开
IPC分类号: G06F9/45 主分类号: G06F9/45
申请人: 甲骨文国?#20351;?#21496;
发明人: J·R·罗斯; B·戈茨; G·斯蒂尔
地址: 美国加利福尼亚
优?#28909;ǎ?/td> 2014.05.13 US 61/992,753; 2015.04.29 US 14/699,129
专利代理机构: 中国国际贸?#29366;?#36827;委员会专利商标事务所 11038 代理人: ?#36153;?#24070;
PDF完整版下载: PDF下载
法律状态
申请(专利)号:

CN201580026936.4

授权公告号:

|||

法律状态公告日:

2017.06.06|||2017.05.10

法律状态类型:

实质审查的生效|||公开

摘要

在一种解决途径中,一种方法包括接收指定将特定值类型的值指派到多个容器中的特定容器的一个或多个较高级别的指令,其中所述多个容器表示用于在代码块的执行期间维护一个或多个变量的数据结构,其中所述多个容器中的至少两个容器具有不同的尺寸;基于根据特定值类型将一个或多个指派规则应用到一个或多个较高级别的指令来生成将该值指派到特定容器的一个或多个较低级别的指令,以及执行一个或多个较低级别的指令。

权利要求书

1.一种用于通过生成和执行对应的较低级别的指令来实现较高级别的指令的方法,所
述较低级别的指令针对对于所述较高级别的指令?#35813;?#30340;一个或多个存储机构,所述方法包
括:
接收指定将特定值类型的值指派到多个容器中的特定容器的一个或多个较高级别的
指令,其中所述多个容器表示用于在代码块的执行期间维护一个或多个变量的数据结构,
其中所述多个容器中的至少两个容器具有不同的尺寸;
基于根据所述特定值类型将一个或多个指派规则应用于所述一个或多个较高级别的
指令,生成将所述值指派到所述特定容器的一个或多个较低级别的指令;
执行所述一个或多个较低级别的指令;
其中所述方法由一个或多个计算设备执行。
2.如权利要求1所述的方法,其中所述一个或多个指派规则包括以下中的一个或多个:
限制哪些值类型能够被指派到所述特定容器的?#38469;?br />在向所述特定容器中加载所述值的拆箱表示或?#21592;?#25345;所述值的第二容器的引用之间
进行选择的规则。
3.如权利要求2所述的方法,其中在向特定容器中加载所述值的所述拆箱表示或?#21592;?br />持所述值的第二容器的引用之间进行选择的规则基于以下中的一项或多项:所述值是否是
不可变的、所述值是否能够适配在所述特定容器内、所述值是否超出了特定的尺寸阈值、所
述多个容器中的另一个容器是否已经存储了所述值、所述值的组成成?#20540;?#24615;质、或者所述
一个或多个较低级别的指令将如何利用所述值。
4.如权利要求2-3中的任一项所述的方法,其中所述多个容器被存储在为多个线程中
的特定线程预留的存储器位置中,并且所述第二容器在由所述多个线程共享的存储器位置
中位于所述多个容器的外部。
5.如权利要求2-4中的任一项所述的方法,其中所述?#38469;?#22522;于以下中的一项或多项:
(1)确定所述特定容器已经被分配为适配一个或多个值类型,并且将对所述特定容器
的指派限制为所述一个或多个值类型的值,
(2)将对所述特定容器的指派限制为与所述特定容器共享尺寸的值或具有比所述特定
容器小的尺寸的值,
(3)将对所述特定容器的指派限制为一个或多个特定值类型直至接收到重置所述特定
容器的指令。
6.如权利要求2-5中的任一项所述的方法,还包括:
响应于确定要在所述特定容器中加载所述值的所述拆箱表示以及确定所述特定容器
不能适配所述值,调整所述特定容器的尺寸以适配所述值。
7.如权利要求1-6中的任一项所述的方法,还包括:
接收指定改变第二特定容器中存储的第二值的组成部?#20540;?#19968;个或多个第二较高级别
的指令,其中所述第二值具有第二特定值类型;
至少部?#20540;?#22522;于与所述第二特定值类型相关联的元数据来生成识别所述第二特定容
器的与所述成分部分对应的部?#20540;?#21333;个较低级别的指令;
执行所述单个较低级别的指令。
8.如权利要求7所述的方法,其中识别所述第二特定容器的所述部分包括以下中的一
项或多项:使用对应于所述第二特定值类型的值类型定义的字段定义来定位所述部分,使
用所述值类型定义的访问控制信息来实行对所述部?#20540;?#35775;问限制,或者基于所述值类型定
义来执行类型检查。
9.如权利要求1-8中的任一项所述的方法,还包括:
接收指定访?#23454;?#20108;特定容器中存储的第二值的组成部?#20540;?#19968;个或多个第二较高级别
的指令,其中所述第二值具有第二特定值类型;
基于与所述第二特定值类型相关联的元数据来确定对所述组成部?#20540;?#35775;问是否应当
是原子的;
响应于确定对所述组成部?#20540;?#35775;问应当是原子的,确定所述组成部分是否存储在不可
变容器中;
响应于确定所述组成部?#25191;?#20648;在不可变容器中,生成不提供原子保证的一个或多个第
二较低级别的指令并且执行所述一个或多个第二较低级别的指令;
响应于确定所述组成部分没有存储在不可变容器中,选择能够提供对所述组成部?#20540;?br />原子访问的一个或多个机制中的特定机制,基于所述特定机制生成提供原子保证的一个或
多个第三较低级别的指令,以及执行所述一个或多个第三较低级别的指令。
10.如权利要求9所述的方法,其中所述第二值存储在第一容器中,并且所述方法还包
括:
响应于确定所述组成部分没有存储在不可变容器中,确定所述组成部?#20540;?#35775;问频率是
否超过访问阈值;
响应于确定所述组成部?#20540;?#25152;述访问频?#39135;?#36807;所述访问阈值,将所述组成部?#25191;?#20648;在
分开的第二容器中并且针对所述组成部分在所述第一容器中存储对所述第二容器的引用。
11.如权利要求9-10中的任一项所述的方法,其中能够提供对所述组成部?#20540;脑?#23376;访
问的所述一个或多个机制基于由所述一个或多个计算设备的一个或多个处理器支?#20540;?#19968;
组指令。
12.存储有指令的一个或多个计算机可?#20004;櫓剩?#25152;述指令当被一个或多个计算设备执
行时使得执行如权利要求1-11中的任一项所述的步骤。
13.一种?#20302;常?#35813;?#20302;?#21253;括一个或多个计算设备,所述一个或多个计算设备包括至少部
?#20540;?#30001;计算硬件实?#20540;摹?#34987;配置为实现如权利要求1-11中的任一项所述的步骤。

说明书

处理值类型

?#38469;?#39046;域

实施例一般涉及用于在编程语?#38405;?#25903;持和/或利用值类型结构体的?#38469;酢?br />

背景?#38469;?br />

计算机语言提供许多不同的方法来创建聚合类型(aggregate type)。例如,诸如
Java之类的语言提供具有标识(identity)的异构聚合(例如,“类”)?#36884;?#26377;标识的同构聚合
(例如,“数组”)。标识由诸如唯一地识别对象的标识号(例如,存储器地址)之类的每个实例
化对象所包括的头部信息来实现。然而,对象标识具有占用空间(footprint)和性能成本,
这是Java具有存储在适当的位置、在方法调用期间在不使用引用的情况下通过值传递、并
且不包括头部的原生类型(primitive type)的主要原因。这与引用类型相反,引用类型由
指针访问、使用在方法调用期间通过值传递的引用来表示、并且包括头部。对于不具?#34892;?#22810;
字段来分摊支持标识所需的额外成本的小对象来说,支持标识的成本是最难以负担的。

例如,考虑具有类型为整型(int)的x和y字段的Point类。在实施方式中,每个
Point对象可以包括额外的对象头部(8到16?#32440;?和引用(4到8?#32440;?的Point对象数组意味
着这些8?#32440;?#30340;数据(对于x和y整数)占用20到32?#32440;?#30340;堆空间。此外,遍历该数组意味着对
于所访问的每个Point对象的指针解引用。这破坏了数组的内在局部性(inherent
locality)并且限制了程序性能。

程序员经常采取?#28909;?#23558;Point数组表示为两个整型数组(一个用于x并且一个用于
y)的技巧来避免这些成本,但是该方法牺牲了封装性(和可维护性)只是为了?#22815;?#26631;识的性
能损失。一种方法是显著扩大语言支?#20540;脑?#29983;的数量。然而,(如果有可能的话)可能难以预
期高效地解决放在程序员面前的每个问题将需要的原生类型。因此,落在原生类型和对象
的领域之间的结构体将对程序员有很大益处。

附图说明

在附图的图?#22411;?#36807;示例的方式而不是限制的方式示出了本发明,在附图中相似的
附图标记指代相似的要素,其中:

图1示出了可以实践本文所描述的?#38469;?#30340;示例性计算架构。

图2是示出了适于实现本文所描述的方法和特征的计算机?#20302;?#30340;一个实施例的框
图。

图3示出了根据实施例的以框图形式的示例性虚拟机存储器布局。

图4示出了根据实施例的以框图形式的示例性帧。

图5示出了根据实施例的用于在容器中存储值类型的过程。

图6示出了根据实施例的用于访问值类型的过程流。

图7是示出了可以实现本发明的实施例的计算机?#20302;?#30340;框图。

具体实施方式

在下面的描述中,出于解释的目的,阐述了许多具体?#38468;?#20197;便提供?#21592;?#21457;明的深
入理解。然而,显而易见,可以在没有这些具体?#38468;?#30340;情况下实践本发明。在其他实例中,公
知的结构和设备以框图形式示出,以避免不必要地混淆本发明。

本文根据以下提纲描述实施例:

1.0总体概述

2.0示例性操作环境

2.1示例性类文件结构

2.2示例性虚拟机架构

2.3加载、链接和初始化

3.0值类型概述

3.1用例

3.2示例性值类型特性

3.3示例性限制

3.4指针管理

3.5示例性定义

3.6示例性用法

3.7示例性实现?#38468;?br />

3.8示例性?#32440;?#30721;和类型描述符

3.9装箱和对象互操作性

3.10示例性代码

3.11附加的示例性选项

3.12类型到值类型的迁移

3.13更新字段的值

4.0修改后的加载进程

5.0存储考虑

5.1存储过程流

6.0原子操作

7.0硬件概述

8.0扩展和替代

9.0第一附加公开

10.0第二附加公开

1.0总体概述

本文所描述的?#38469;?#32463;常使用来自Java编程语言、Java虚拟机(“JVM”)和Java运行
环境的术语和定义。然而,构想的是所描述的?#38469;?#21487;以结?#20808;?#20309;编程语言、虚拟机架构或运
行环境来使用。因此,例如诸如“方法”之类的按Java术语描述的用辞可与诸如“函数”之类
的其他用辞互换。此外,术语“方法”还与术语“类方法”或“对象方法”同义。方法是由名称指
代并且可以在使得方法的代码被执行的程序中的各?#20540;?#22788;调用(援用)的一组代码或代码
块。

在实施例中,值类型是遵循“像类一样编程,像整型一样工作”原则的一种类别的
聚合体。因此,像类一样,值类型可以由程序员按照被命名的、类型成分(字段)、行为(方
法)、隐私(访问控制)、编程初始化(构造函数(constructor))等来定义。然而,像原生类型
(诸如整型)一样,值类型不包含头部信息并?#20918;揮行?#22320;当作用户定义的原生。因此,当可行
时,值类型被存储为扁平化的表示并且在方法之间通过值传递。因此,与对象相比,通过不
要求指针被解引用以访问值类型实?#33267;?#36895;度改进,并且通过不要求值类型存储头部信息实
?#33267;?#23384;储改进。然而,实施例自由地以许多方式实现值类型的方面,这些方式中的一些方式
可以违背“像类一样编程,像整型一样工作”原则。因此,本文所描述的值类型的特征可以被
分开实现、作为整体实现或者无限制地以任何组合实现。

然而,为了实现值类型,存在若干考虑。一个考虑是如何在源语言和/或虚拟机的
指令集(当适用时)中显现(surface)值类型。例如,由于值类型不包含具有标识信息的头
部,因此?#35272;?#20110;标识的许多特征要么对于值类型必须被禁用,要么在值类型的背景下必须
被分配新含义。作为另一示例,附加的指令和/或关键字可以被添加到源语言/虚拟机指令
集以定义和利用值类型。节3.0“值类型概述”及其相关小节一般涉及如何在源语言和/或虚
拟机的指令集中显现值类型的问题。

另一个考虑是如何在诸如虚拟机的运行环?#25345;?#31867;的计算机?#20302;?#30340;工作存储器内
处理值类型的存储。如上文提到的,旨在以扁平化的表示来存储值类型。因此,例如如果对
象具有存储值类型的字段,则旨在将该值类型在没有指针间接寻址(pointer
indirection)的情况下存储在适当的位置。作为另一示例,当值类型被加载到栈帧(stack
frame)中的局部变量中时,该值类型被扁平地存储在表示局部变量的容器中。然而,因为值
类型可以具有可变的尺寸,所以存在容器可能需要被调整尺寸以便容纳特定的值类型的情
况。这造成了性能问题,因为为容器重新分配内存可能带来大量开销,尤其是当重新分配经
常被执行的时候。

因此,在一些实施例中,实现优化以?#28304;?#20648;值类型的成本设定界限。例如,虚拟机
的验证器可以定义若干指派规则,当接收到在容器中放置值类型的指令时检查这些指派规
则。例如,验证器可以阻止将被分配为针对一种值类型的容器用于存储具有不同尺寸的值
类型。因此,阻止了虚拟机不断地重新分配容器以适配不同的值类型。作为另一示例,如果
值类型超出了尺寸阈值并?#20918;?#30830;定为是不可变的,则虚拟机可以选择在所管理的堆存储器
上存储值类型并且替代地在容器中存储对堆的引用。因此,阻止了虚拟机引起多次复制过
大的值类型的开销。例如,如果局部变量被放置在操作数栈上,则该局部变量可以通过引用
而不是通过值被复制。然而,由于值类型是不可变的,因此对终端用户而言,指令的行为(从
语义的角度)无法与其中值类型被存储并通过值传递的情况分辨开来。这可能导致访问的
时间增加,但是对于大的值类型来说,复制花费的时间量可能大大超过去除指针遍历的益
处。节5.0“存储考虑”及其相关小节一般涉及存储优化和性能的问题。

在一些实施例中,值类型是不可变的,意味着值类型(至少从终端用户的视角)不
能以分段的方式更新。这类似于诸如Java之类的一些语言怎样允许由变量保?#20540;?#25972;数被替
换,但是不向用户提供允许整数的单个位改变值的指令。因此,在值类型的背景下,不可变
性意味着值类型仅可以作为整体被替换。然而,即使当值类型为不可变时,值类型也仍然可
以被存储在可变的变量或容器中。在变量、字段或容器的背景下,不可变性暗示着由该变量
或容器保?#20540;?#20540;不能被替换(例如,被冻结)。

另一考虑是如何阻止值类型在被多个线程访问时的撕?#36873;?#20551;设值类型被存储在诸
如许多虚拟机实现方式的堆之类的共享存储器中,由于多个线程同时访问值类型,因此存
在竞争状况(race condition)的风险。由于值类型旨在充当诸如原生整型之类的整个值,
因?#35828;?#31532;一线程试图更新存储值类型的容器并?#19994;?#20108;线程在第一线程完全结束更新之前
读取该容器时,结构撕裂发生。结果,第二线程在容器中遇到部分是旧值并?#20063;?#20998;是新值的
值类型。为了阻止结构撕裂,?#38469;?#34987;应用以使得存储和加载操作是原子的。然而,由于值类
型是用户定义的,因此执行原子访问的合适方法可能基于值类型的尺寸和/或用途以及底
层计算机?#20302;?#30340;硬件能力而变化。例如,一些中央处理单元(CPU)支持针对各种尺寸(例如,
64位、128位、256位等)的原子更新和/或事务,但是这些硬件指令不能考虑可能被用于值类
型的每个尺寸。因此,因为值类型可以大于底层硬件支?#20540;?#26368;大原子存储器转移,所以结构
撕裂变得有可能,这是因为(例如)对4成分值的写入可以被拆成两个64位写入,而该值的读
取可以被拆成两个64位读取。因此,如果读取和写入这二者同时执行,则有可能遇到作为旧
值和新值的混合的值类型。

在实施例中,使用若干?#38469;?#26469;优化针对值类型的原子操作。例如,如果硬件指令可
用于执行原子操作,则该指令是优选的,因为硬件实?#20540;募际?#19982;软件实?#20540;募际?#30456;比一般
具有更好的性能。此外,在某些情形中,原子操作可以被绕过,诸如当被访问的字段为不可
变时。在一些实施例中,当值类型的字段被频繁访问时,值类型被修改以将该字段放置在由
指针引用访问的单独的容器中。通过创建更新后的值的拷贝并且切换指针,可以相对快地
执行对通过指针访问的字段的原子更新。因此,通过修改值类型的结构,当执行原子访问时
可以获得提高的性能。节6.0“原子操作”一般针对涉及原子操作的问题。

2.0示例性操作架构

图1示出了可以实践本文所描述的?#38469;?#30340;示例计算架构100。

如图1中所示,计算架构100包括源代码文件101,源代码文件101由编译器102编译
为表示要被执行的程序的类文件103。类文件103然后由执行平台112加载并且执行,执行平
台112包括运行环境113、操作?#20302;?11以及使得能够实现运行环境113和操作?#20302;?11之间
的通信的一个或多个应用编程接口(API)110。运行环境113包括虚拟机104,虚拟机104包括
各种组件,诸如存储器管理器105(其可以包括垃圾收集器)、用于检查类文件103和方法指
令的合法性的验证器106、用于定位和建立类的存储器中(in-memory)表示的类加载器107、
用于执行虚拟机104代码的解释器108以及用于产生优化的机器级别代码的即时(JIT)编译
器109。

在实施例中,计算架构100包括源代码文件101,源代码文件101包含以诸如Java、
C、C++、C#、Ruby、Perl等之类的特定编程语言编写的代码。因此,源代码文件101遵守用于相
关语言的一组特定的语法和/或语义规则。例如,以Java编写的代码遵守Java语言规范。然
而,由于规?#31471;?#26102;间而被更新和修订,因此源代码文件101可以与版本号相关联,该版本号
指示源代码文件101所遵守的规范的修订版本。被用于编写源代码文件101的确切的编程语
言一般不关键。

在各种实施例中,编译器102把根据依照程序员的方便的规范编写的源代码转换
成可由特定机器环?#25345;?#25509;执行的机器代码或对象代码,或者转换成可由能够在多种特定机
器环?#25104;?#36816;行的虚拟机104执行的中间表示(“虚拟机代码/指令”),诸如?#32440;?#30721;。虚拟机指
令可由虚拟机104以比源代码更直接、更高效的方式执行。将源代码转换为虚拟机指令包括
将来自语言的源代码功能?#25104;?#21040;利用诸如数据结构之类的底层资源的虚拟机功能。时常
地,由程序员经由源代码以简单术语呈?#20540;?#21151;能被转换成更复杂的步骤,该更复杂的步骤
更直接地?#25104;淶接?#34394;拟机104驻留在其上的底层硬件支?#20540;?#25351;令集。

一般来说,程序要么作为编译后的程序执行,要么作为解释后的程序执行。当程序
被编译时,在执行之前代码从第一语?#21592;?#20840;?#20540;?#36716;变为第二语言。由于转变代码的工作是
提前执行的,因此编译后的代码往往具有杰出的运行时性能。另外,由于在执行之前所述转
变全?#20540;?#21457;生,因此可以使用诸如常量折叠、死代码消除、内联等之类的?#38469;?#26469;分析和优化
代码。然而,取决于正被执行的程序,启动时间可能是显著的。另外,插入新代码将会要求程
序离线、重新编译和重新执行。对于被设计为允许在程序的执行期间插入代码的许多动态
语言(诸如Java)来说,纯编译的方法一般是不合适的。当程序被解释时,程序的代码在程序
执行的同时被逐行读取并?#26131;?#25442;为机器级别的指令。结果,程序具有短的启动时间(可以几
乎立刻开始执行),但是运行中执行转换减弱了运行时性能。此外,由于每个指令被单独分
析,因此?#35272;?#20110;对程序的更全?#20540;?#20998;析的许多优化不能执行。

在一些实施例中,虚拟机104包括解释器108和JIT编译器109(或者实现这二者的
方面的组件),并且使用解?#22270;际?#21644;编译?#38469;?#30340;组合来执行程序。例如,虚拟机104最初可以
开始于经由解释器108解释表示程序的虚拟机指令并同时追踪关于程序行为的统计数据,
诸如虚拟机104执行不同的代码部分或代码块的频率。一旦代码块超过某一阈值(它是“热
的”),则虚拟机104调用JIT编译器109来执行对块的分析并且生成替换“热”代码块的经优
化的机器级别的指令以供将来执行。由于程序往往花费其大部分时间来执行它们的整体代
码的小部分,因?#31169;?#32534;译程序代码的“热”部分可以提供与完全编译的代码相似的性能,但
是没有启动的损失。此外,尽管优化分析局限于被替换的“热”块,但是仍然存在与独个地转
换每个指令相比大得多的优化潜力。

为了提供清楚的示例,源代码文件101被示为要由执行平台111执行的程序的“最
高级别”表示。然而,尽管计算架构100将源代码文件101描绘为“最高级别”程序表示,但是
在其他实施例中源代码文件101可以是经由“较高级别”编译器接收的中间表示,该“较高级
别”编译器将不同语言的代码文件处理成源代码文件101的语言。为了示出清楚的示例,以
下公开假设源代码文件101遵守基于类的面向对象的编程语言。然而,这不是利用本文所描
述的特征的要求。

在实施例中,编译器102接收源代码文件101作为输入并且将源代码文件101转换
成虚拟机104所期望的格式的类文件103。例如,在JVM的背景下,Java虚拟机规范的第4章定
义了期望类文件103遵守的特定类文件格式。在一些实施例中,类文件103包含已经从源代
码文件101转换而来的虚拟机指令。然而,在其他实施例中,类文件103还可以包含其他结
构,诸如标识关于各种结构(类、字段、方法等)的常量值和/或元数据的表。

以下?#33268;?#23558;假设类文件103中的每个类文件表示在源代码文件101中定义的(或者
由编译器102或虚拟机104动态生成的)各个“类”。然而,前面提到的假设不是严格的要求并
且将取决于虚拟机104的实现方式。因此,不管类文件103的确切格式如何,仍然可以执行本
文所描述的?#38469;酢?#22312;一些实施例中,类文件103被划分成一个或多个“库”或“包?#20445;?#20854;中每个
“库”或“包”包括提供相关功能的一批类。例如,一个库可以包含实现输入/输出(I/O)操作、
数学工具、密码?#38469;酢?#22270;形实用程序等的一个或多个类文件。此外,一些类(或者这些类内的
字段/方法)可以包括访问限制,该访问限制将其使用限制在特定的类/库/包内或者限制在
具有适当许可的类内。

2.1示例性类文件结构

图2示出了根据实施例的以框图形式的关于类文件200的示例性结构。为了提供清
楚的示例,本公开的余下部分假设计算架构100的类文件103遵守本节中所描述的示例性类
文件200的结构。然而,在实际环境中,类文件200的结构将取决于虚拟机104的实现方式。此
外,本文所?#33268;?#30340;一个或多个特征可以修改类文件200的结构以例如添加附加结构类型。因
此,对于本文所描述的?#38469;?#26469;说,类文件200的确切结构不是关键的。出于节2.1的目的,
“类”或“该类”是指由类文件200表示的类。

在图2中,类文件200包括常量表201、字段结构208、类元数据204和方法结构209。

在实施例中,常量表201是除其他功能之外还充当类的符号表的数据结构。例如,
常量表201可以存储与源代码文件101中使用的各种识别符(诸如类型、?#27573;А?#20869;容和/或位
置)相关的数据。常量表201具有用于由编译器102从源代码文件101导出的值结构202(表示
整型、长整型、双精度型(double)、浮点型、?#32440;?#22411;、?#22336;?#20018;型等类型的常量值)、类信息结构
203、名称和类型信息结构205、字?#25105;?#29992;结构206以及方法引用结构207的条目。在实施例
中,常量表201被实现为将索引i?#25104;?#21040;结构j的数组。然而,常量表201的确切实现方式不是
关键的。

在一些实施例中,常量表201的条目包括对其他常量表201条目进行索引的结构。
例如,用于表示?#22336;?#20018;的值结构202之一的条目可以保持将其“类型”标识为?#22336;?#20018;的标签
以及?#28304;?#20648;表示该?#22336;?#20018;的ASCII?#22336;?#30340;?#22336;?#22411;、?#32440;?#22411;或整型值的常量表201的一个或多
个其他值结构202的索引。

在实施例中,常量表201的字?#25105;?#29992;结构206保持对常量表201中表?#24452;?#20041;字段的
类的类信息结构203的索引以及对常量表201中提供字段的名称和描述符的名称和类型信
息结构205的索引。常量表201的方法引用结构207保持对常量表201中表?#24452;?#20041;方法的类的
类信息结构203的索引以及对常量表201中提供方法的名称和描述符的名称和类型信息结
构205的索引。类信息结构203保持对常量表201中保持相关类的名称的值结构202的索引。
名称和类型信息结构205保持对常量表201中存储字段/方法的名称的值结构202的索引以
及对常量表201中存储描述符的值结构202的索引。

在实施例中,类元数据204包括用于类的元数据,诸如版本号、常量池中的条目的
数量、字段的数量、方法的数量、访?#26102;?#24535;(类是否是公有的(public)、?#25509;?#30340;(private)、最
终的(final)、抽象的(abstract)等)、对常量表201的类信息结构203中标识该类的一个类
信息结构的索引、对常量表201的类信息结构203中标识超类(如果有的话)的一个类信息结
构的索引等?#21462;?br />

在实施例中,字段结构208表示标识类的各个字段的一组结构。字段结构208针对
类的每个字?#26410;?#20648;关于该字段的访问器标志(字段是否是公有的、?#25509;?#30340;、最终的、抽象的
等)、对常量表201中保持字段的名称的值结构202的索引、以及对常量表201中保持字段的
描述符的值结构202的索引。

在实施例中,方法结构209表示标识类的各个方法的一组结构。方法结构209针对
类的每个方法存储关于该方法的访问器标志(方法是否是静态的、公有的、?#25509;?#30340;、同步的
等)、对常量表201中保持方法的名称的值结构202的索引、对常量表201中保持方法的描述
符的值结构202的索引、以及与如源代码文件101中定义的方法主体对应的虚拟机指令。

在实施例中,描述符表示字段或方法的类型。例如,描述符可以被实现为遵守特定
语法的?#22336;?#20018;。尽管确切的语法不是关键的,但是下文描述了几个示例。

在描述符表示字段的类型的示例中,描述符标识由字段保?#20540;?#25968;据的类型。在实
施例中,字段可以保持基本类型、对象或数组。当字段保持基本类型时,描述符是标识该基
本类型的?#22336;?#20018;(例如,“B?#20445;絙yte(?#32440;?#22411;)、“C?#20445;絚har(?#22336;?#22411;)、“D?#20445;絛ouble(双精度
型)、“F?#20445;絝loat(浮点型)、“I?#20445;絠nt(整型)、“J?#20445;絣ong int(长整型)等)。当字段保持对象
时,描述符是标识对象的类名称的?#22336;?#20018;(例如,“L ClassName”)。在该情况中“L”指示引
用,因此“L ClassName”表?#24452;?#31867;ClassName的对象的引用。当字段是数组时,描述符标识由
数组保?#20540;?#31867;型。例如,“[B”指示?#32440;?#22411;的数组,其中“[”指示数组而“B”指示该数组保持字
节型的基本类型。然而,由于数组可以?#30701;祝?#22240;此关于数组的描述符还可以指示?#30701;住?#20363;如,
“[[L ClassName”指示数组,在该数组中每个索引保持保持类ClassName的对象的数组。在
一些实施例中,ClassName是完全限定的(fully qualified)并且包括类的简单名称以及类
的路径名称。例如,ClassName可以指示文件存储在托管类文件200的包、库或文件?#20302;?#20013;的
何处。

在方法的情况中,描述符识别方法的参量和方法的返回类型。例如,方法描述符可
以遵循一?#38408;?#24335;“({ParameterDescriptor})ReturnDescriptor?#20445;?#20854;中
{ParameterDescriptor}是表示参量的字段描述符的列表,而ReturnDescriptor是标识返
回类型的字段描述符。例如,?#22336;?#20018;“V”可以被用于表示空(void)返回类型。因此,在源代码
文件101中被定义为“Object m(int I,double d,Thread t){…}”的方法匹配描述符“(I D
L Thread)L Object”。

在实施例中,方法结构209中所保?#20540;?#34394;拟机指令包括引用常量表201的条目的操
作。

使用Java作为示例,考虑下面的类:


在上面的示例中,Java方法add12and13被定义在类A中、不带参数并且返回整数。
方法add12and13的主体调用以常量整数值12和13作为参数的类B的静态方法addTwo,并且
返回结果。因此,在常量表201中,编译器102除其他条目之外还包括与对方法B.addTwo的调
用对应的方法引用结构。在Java中,对方法的调用向下编译为JVM的?#32440;?#30721;中的invoke命令
(在该情况中是invokestatic,因为addTwo是类B的静态方法)。invoke命令被提供了对常量
表201中与标识定义addTwo的类“B”的方法引用结构对应的索引、addTwo的名称“addTwo?#24065;?br />及addTwo的描述符“(I I)I”。例如,假设前面提到的方法引用被存储在索引4处,则?#32440;?#30721;
指令可以表现为“invokestatic#4”。

由于常量表201利用承载有标识信息的结构以符号形式指代类、方法和字段,而不
是利用?#28304;?#20648;器位置的直接引用,因此常量表201的条目被称为“符号引用”。符号引用被用
于类文件103的一个原因是因为:在一些实施例中,编译器102不了解类一旦被加载到运行
环境113中将怎样被存储以及将被存储在何处。如将在节2.3中描述的,在被引用的类(以及
相关结构)已经被加载到运行环境中并且已经被分配了具体的存储器位置之后,最终,符号
引用的运行时表示由虚拟机104解析为实际的存储器地址。

2.2示例性虚拟机架构

图3示出了根据实施例的以框图形式的示例性虚拟机存储器布局300。为了提供清
楚的示例,余下?#33268;?#23558;假设虚拟机104遵守图3中描绘的虚拟机存储器布局300。另外,尽管
虚拟机存储器布局300的组成部分可以被称为存储器“区域?#20445;?#20294;是不要求存储器区域是相
邻的。

在图3示出的示例中,虚拟机存储器布局300被划分成共享区域301和线程区域
307。

共享区域301表示存储器中在虚拟机104上执行的各个线程之间共享的结构被存
储的区域。共享区域301包括堆302和每个类的区域303。在实施例中,堆302表示从中分配用
于类实例和数组的存储器的运行时数据区域。在实施例中,每个类的区域303表示存储属于
独个类的数据的存储器区域。在实施例中,对于每个加载的类,每个类的区域303包括表示
来自类的常量表201的数据的运行时常量池304、字段和方法数据306(例如,用于保持类的
静态字段)以及表示用于类的方法的虚拟机指令的方法代码305。

线程区域307表示存储特定于独个线程的结构的存储器区域。在图3中,线程区域
307包括表示由不同线程利用的每个线程结构的线程结构308和线程结构311。为了提供清
楚的示例,图3中描绘的线程区域307假设两个线程正在虚拟机104上执行。然而,在实际环
境中,虚拟机104可以执行任何?#25105;?#25968;量的线程,其中线程结构的数量相应地缩放。

在实施例中,线程结构308包括程序计数器309和虚拟机栈310。类似地,线程结构
311包括程序计数器312和虚拟机栈313。在实施例中,程序计数器309和程序计数器311存储
正由它们各自的线程执行的虚拟机指令的当前地址。因此,当线程逐句通过(step
through)指令时,程序计数器被更新以维护对当前指令的索引。在实施例中,虚拟机栈310
和虚拟机栈313各?#28304;?#20648;它们各自的用于保持局部变量和部分结果的帧(frame),并?#19968;?#34987;
用于方法调用和返回。

在实施例中,帧是用于存储数据和部分结果、返回用于方法的值以及执行动态链
接的数据结构。每次调用方法时就创建新帧。当使得帧被生成的方法完成时,帧被销毁。因
此,当线程执行方法调用时,虚拟机104生成新帧,并且将该帧推?#25509;?#32447;程相关联的虚拟机
栈上。当方法调用完成时,虚拟机104将方法调用的结果传递回前一帧并且使当前帧出栈。
在实施例中,对于给定的线程,在任何时间点处有一个帧是活动的。该活动的帧被称为当前
帧,使得生成当前帧的方法被称为当前方法,而当前方法所属的类被称为当前类。

图4示出了根据实施例的以框图形式的示例性帧400。为了提供清楚的示例,余下
?#33268;?#23558;假设虚拟机栈310和虚拟机栈313的帧遵守帧400的结构。

在实施例中,帧400包括局部变量401、操作数栈402和运行时常量池引用表403。

在实施例中,局部变量401被表示为各自保?#31181;?#22914;?#32423;?#22411;、?#32440;?#22411;、?#22336;?#22411;、短整
型、整型、浮点型、引用型等之类的值的变量的数组。此外,诸如长整型或双精度型之类的一
些值类型可以由数组中的多于一个条目表示。局部变量401被用于在方法调用时传递参数
以及存储部分结果。例如,当响应于调用方法而生成帧400时,参数可以被存储在局部变量
401内的预定位置中,诸如与调用中的第一个到第N个参数对应的索引1-N。

在实施例中,当虚拟机104创建帧400时,操作数栈402默认是空的。然后虚拟机104
供应来自当前方法的方法代码305的指令以将来自局部变量501的常量或值加载到操作数
栈502上。其他指令?#30828;?#20316;数栈402取出操作数、?#36816;?#20204;进行操作并且将结果推到操作数栈
402上。此外,操作数栈402被用于准备要被传递到方法的参数以及接收方法结果。例如,在
发出对方法的调用之前,正被调用的方法的参数可以被推到操作数栈402上。然后虚拟机
104生成用于方法调用的新帧,其中前一帧的操作数栈402上的操作数出栈并?#20918;?#21152;载到新
帧的局部变量401中。当被调用的方法终止时,新帧?#26377;?#25311;机栈出栈并且返回值被推回前一
帧的操作数栈402上。

尽管使用诸如“数组”和/或“栈”之类的数据结构来提及局部变量401和操作数栈
402,但是对用于实现这些元素的数据结构的类型没有限制。另外,关于局部变量401和操作
数栈402在此提及的数据结构涉及数据结构的高级别表示。实施例可以使用各种较低级别
的存储机制来实现这些数据结构,诸如将局部变量401和/或操作数栈402的一个或多个值
存储在执行虚拟机104的机器硬件的中央处理单元(CPU)的一个或多个寄存器中。较低级别
的指令可以引用对于较高级别的指令来?#20302;该?#30340;一个或多个较低级别的存储机制。尽管可
以使用各种较低级别的存储机制(这些较低级别的存储机制都不是由较高级别的指令指定
的)来实现较高级别的指令,但是较低级别的指令引用用于实现较高级别的指令的一个或
多个特定存储机制。

在实施例中,运行时常量池引用表403包含对当前类的运行时常量池304的引用。
运行时常量池引用表403被用于支持解析。解析是这样的过程?#21644;?#36807;该过程,常量池304中的
符号引用被翻译为具体的存储器地址,按照需要加载类以解析尚未定义的符号并且将变量
访问翻译成与这些变量的运行时位置相关联的存储结构中的合适的偏移。

2.3加载、链接和初始化

在实施例中,虚拟机104动态地加载、链接和初始化类。加载是寻找具有特定名称
的类并且在运行环境113的存储器内创建来自该类的相关联的类文件200的表示的过程。例
如,在虚拟机存储器布局300的每个类的区域303内为该类创建运行时常量池304、方法代码
305以及字段和方法数据306。链接是采用类的存储器中表示并且将其与虚拟机104的运行
时状态组合以使得类的方法可以被执行的过程。初始化是执行类构造函数以设置类的字段
和方法数据306的起始状态和/或为被初始化的类在堆302上创建类实例的过程。

以下是可以由虚拟机104实?#20540;?#21152;载、链接和初始化?#38469;?#30340;示例。然而,在许多实
施例中步骤可以交错,以使?#36152;?#22987;类被加载,然后在链接期间第二个类被加载以解析在第
一个类中发?#20540;?#31526;号引用,这又使得第三个类被加载,等?#21462;?#22240;此,通过加载、链接和初始化
的阶段的进程可以根据类而有所不同。此外,一些实施例可以?#26144;?“懒惰地”执行)加载、链
接和初始化过程的一个或多个功能直至该类被实际要求。例如,方法引用的解析可以被延
迟直至调用被引用的方法的虚拟机指令被执行。因此,对于每个类何时执行步骤的确切时
机在实施方式之间可以差别很大。

为了开始加载过程,虚拟机104通过调用加载初始类的类加载器107而启动。用于
指定初始类的?#38469;?#23558;随着实施例不同而变化。例如,一种?#38469;?#21487;以使虚拟机104在启动时接
受指定初始类的命令行参数。

为了加载类,类加载器107解析对应于类的类文件200并且确定类文件200是否为
格式良好的(满?#38408;?#25311;机104的语法期待)。如果类文件200不是格式良好的,则类加载器107
生成错误。例如,在Java中,可能以异常的形式生成错误,该异常被抛给异常处理器以供处
理。否则,类加载器107通过在每个类的区域303内分配用于该类的运行时常量池304、方法
代码305以及字段和方法数据306来生成该类的存储器中表示。

在一些实施例中,当类加载器107加载类时,类加载器107还递归加载被加载的类
的超类。例如,虚拟机104可以确保:在进行对于特定类的加载、链接和初始化过程之前,该
特定类的超类被加载、链接和/或初始化。

在链接期间,虚拟机104验证类、准备类并且执行类的在运行时常量池304中定义
的符号引用的解析。

为?#25628;?#35777;类,虚拟机104检查类的存储器中表示在结构上是否是正确的。例如,虚
拟机104可以检查除了泛型类对象之外的每个类具有超类、检查最终类不具有子类以及最
终方法没有被重载、检查当前类是否具有对于常量池304中所引用的类/字段/结构的正确
的访问许可、检查方法的虚拟机104代码将不会引发意外行为(例如,确保跳转指令不会使
虚拟机104超出方法的末尾),等?#21462;?#22312;验证期间执行的确切检查取决于虚拟机104的实现方
式。在一些情况中,验证可以导致附加的类被加载,但是在继续进行之前不一定要求这些类
还被链接。例如,假设类A包含对类B的静态字段的引用。在验证期间,虚拟机104可以检查类
B以确保所引用的静态字段实际存在,这可能导致类B的加载,但不一定导致类B的链接或初
始化。然而,在一些实施例中,某些验证检查可以被推迟至较晚的阶段,诸如在符号引用的
解析期间被检查。例如,一些实施例可以推迟检查对于符号引用的访问许可直至这些引用
被解析。

为了准备类,虚拟机104将位于该类的字段和方法数据306内的静态字段初始化为
默认值。在一些情况中,将静态字段设置为默认值可以与运行该类的构造函数不同。例如,
验证过程可以在初始化期间将静态字段清零或者将静态字段设置为构造函数希望这些字
段具有的值。

在解析期间,虚拟机104根据类的运行时常量池304中所包括的符号引用来动态地
确定具体的存储器地址。为了解析符号引用,虚拟机104利用类加载器107来加载符号引用
中识别的类(如果还未加载)。一旦该类被加载,则虚拟机104了解所引用的类及其字段/方
法的每个类的区域303内的存储器位置。然后虚拟机104将符号引用替换为对所引用的类、
字段或方法的具体的存储器位置的引用。在实施例中,虚拟机104高速缓存解析以便在当虚
拟机104处理另一个类时遇到相同的类/名称/描述符的情况下重新使用。例如,在一些情况
中,类A和类B可以调用类C的同一方法。因此,当针对类A执行解析时,该结果可以被高速缓
存并且在类B中的相同符号引用的解析期间被重新使用以降低开销。

在一些实施例中,在链接期间解析符号引用的步骤是可选的。例如,实施例可以以
“懒惰的”方式执行符号解析,从而?#26144;?#35299;析的步骤直至需要所引用的类/方法/字段的虚拟
机指令被执行。

在初始化期间,虚拟机104执行类的构造函数以设置该类的起始状态。例如,初始
化可以初始化类的字段和方法数据306以及在由构造函数创建的堆302上生成/初始化任何
类实例。例如,用于类的类文件200可以指定特定方法是用于设立起始状态的构造函数。因
此,在初始化期间,虚拟机104执行该构造函数的指令。

在一些实施例中,虚拟机104通过最初检查字段/方法在所引用的类中是否被定义
来执行对字段和方法引用的解析。否则,虚拟机104针对所引用的方法/字段递归搜索所引
用的类的超类直至字段/方法被定位或到达最高级别的超类,在到达最高级别的超类的情
况下生成错误。

3.0值类型概述

在一些实施例中,虚拟机104提供许多不同的方式来创建聚合类型。例如,虚拟机
104可以提供具有标识的异构聚合(例如,经由“类”)?#36884;?#26377;标识的同构聚合(例如,经由“数
组”)。值类型表示异构的并且没有标识的另一类聚合。因此,类似于原生类型(诸如?#32440;?#22411;、
短整型、整型、长整型、浮点型、双精度型、?#22336;?#22411;和?#32423;?#22411;),如果两个存储器区域包含相同
的值类型,则这些存储器区域中的数据不能被区分。这与在一些实施例中各自包含具有诸
如对象的存储器地?#20998;?#31867;的唯一标识号的头部信息的类对象相反。对象标识具有占用空间
和性能成本,这是与许多其他面向对象的语言不同,Java具有原生类型的主要原因。这些成
?#24452;?#20110;不具?#34892;?#22810;字段来分摊额外成本的小对象来说是非常难以负担的。

在一些实施例中,在占用空间方面,具有标识的对象被分配在堆302上、具有一个
或多个?#20540;?#23545;象头部并且(除非死亡,否则)具有指向它们的一个或多个指针。在性能方面,
每个相异的实例可以被分配在堆302上并且即使对象仅包含单个字段(例如,
java.lang.Integer),每个访问也包括相关的加载(指针遍历)以到达“载荷”。另外,在Java
中,对象头部支持包括Object.getClass、Object.wait和System.identityHashCode的许多
基于标识的操作。

对象标识用来支持可变性,其中对象的状态可以是可变的,但是维持相同的内部
对象。例如,对象的字段可以被修改,但是尽管字段的值发生改变,头部信息仍然将对象识
别为“相同的”。另外,在一些实施例中,对象标识还用来支持多态性。然而,许多编程惯用语
法(idiom)不要求标识,并且由于不付出存储器占用空间、局部性和标识的优化?#22836;?#32780;受
益。尽管有重大的尝试,但是许多虚拟机在解决标识对于程序是否有意义方面仍然较差,并
且因此可能悲观地对于不需要标识的许多对象支持标识。

在一些实施方式中,甚至名义上无状态的(具有所有最终字段的)对象可以即使在
高度优化的代码中使其标?#31471;?#26102;被追踪,以免对象被用作同步的手段或者由?#35272;?#20110;标识的
任何其他机制使用。该内在的“有状态性”妨碍许多优化。在一些情况中,逃逸分析(escape
analysis)?#38469;?#26377;时可以减轻这些成本,但是这些?#38469;?#22312;代码复?#26377;?#38754;前是脆弱的并且在
分开编译的情况下?#36127;?#23436;全失效。

运行示例:Point(点)

考虑Point类:


即使Point是不可变的,虚拟机104也不一定知道Point对象的标识将从来不被使
用(例如,出于同步的目的将对象用作内部锁)。结果,Point被表示为关于x和y的“箱”对象。
在一种实现方式中,Point对象的数组包括额外的对象头部(8到16?#32440;?和引用(4到8字
节),从而意味着这些8?#32440;?#30340;数据(用于x和y整型)占用20到32?#32440;?#30340;堆空间,而迭代该数
组意味着对于所访问的每个Point对象的指针解引用。这破坏了数组的内在局部性并且限
制了程序性能(更不用说分配带来了垃圾收集器的工作)。程序员通常借助于如将点数组表
示为两个整型数组的技巧来避免这些成本,但是这牺牲了封装性(和可维护性)只是为了补
回标识的性能损失。另一方面,如果Point可以用与诸如整型之类的原生类型相同的方式表
示,则虚拟机104可以在寄存器中存储Point、将它们推到栈上、遍历具有局部性的数组以及
使用少得多的存储器,而不损失封装性。

在实施例中,值类型表示没有标识的由用户定义的聚合类型,其可以以源代码文
件101和虚拟机104的指令集的语言中显现,从而在不牺牲封装性的情况下支?#25191;?#20648;器高效
的?#36884;?#37096;性高效的编程惯用语法。在实施例中,值类型是可以包含原生类型、引用类型或者
甚至其他值类型的异构聚合。

在一些实施例中,例如在Java中,用于类的许多定义和封装机构可以被用于容易
且安全地建立基于新的值类型结构体的数据结构。例如,值类型可以被当作特殊标记的并
且受限的类定义的形式。然而,同时,值类型对于虚拟机104的用户来说(在语义的意义上)
仅仅充当新型的原生。

如将在下面的节中探索的,尽管值类型有用地类似于类,但是(像原生那样)在值
类型和引用类型之间做出清楚且?#20302;?#30340;区分是有用的。因此,在一些实施例中,新的指令被
添加到虚拟机104的指令集以创建、发布和/或修改值类型。然而,在其他实施例中,当前指
令被重载,以便根据指令是否对引用、原生类型和/或值类型操作而执行不同的功能。

3.1用例

在实施例中,值类型可以被引入到虚拟机104以支?#20013;?#22810;特征,这些特征在使用基
于标识的聚合的情况下可能不存在或者是以次优方式实?#20540;摹?#28982;而,使用值类型可以高效
地实现以下示例。一些示例包括:

数值(numeric)。诸如JVM之类的一些虚拟机仅提供有限数量的高效数值类型;如
果使用这些数值类型不能高效地解决问题,则必须替代地使用具有标识的聚合(以及相关
联的开销)。?#28909;?#22797;数、扩展精度的整数或无符号整数以及十进制(decimal)类型之类的数
值类型是广泛有用的,但是仅可以?#31245;?#29983;和/或对象类来近似(有损于类型安全性、封装性
和/或性能)。

?#38236;?#31867;型(native type)。现代处理器支?#25351;?#31181;各样的?#38236;?#25968;据类型,并且(像数
值那样)它们中的仅仅一些被直接?#25104;?#20026;虚拟机所支?#20540;脑?#29983;。这使得编写直接编译为诸
如向量指令之类的包含?#38236;?#31867;型的指令的代码是困难的或者不可能的。

代数数据类型。使用对象箱可以实现像Optional<T>或Choice<T,U>那样的数据类
型。然而,就小的无标识的聚合而言,许多这样的类型(尤其是像元组那样的产品类型)具有
自然的表示。单元类型(空类似物(void-like)和度量二者)对于表示代数数据类型有?#24065;?br />是有用的,但前提是它们的占用空间开销可以被显著降低或被驱使为零。

元组。值的元素可以自身被当作值并且不一定需要对象箱。

游标(cursor)。迭代器或其他游标在复制数据结构中并且不一定需要对象箱。此
外,(所管理的和/或?#38236;?#30340;)数据结构的客户机可以在保持完整封装性和类型安全性的情
况下绕过数据结构中的迭代器和其他“智能指针”。

3.2示例性值类型特性

在一些实施例中,在虚拟机104级别处的值类型设施提供以下有益特性中的一个
或多个:

标量化。在一些实施例中,值类型的实例可以被定期分解为它们的成分并且存储
在寄存器或者栈(诸如虚拟机栈310)中,而不是在堆302上。当作为包含对象的部分被存储
在堆302中时,虚拟机104可自由地使用值类型的扁平化的、无指针的表示。

包装(wrapping)。在一些实施例中,值类型具有拆箱表示和装箱表示这二者。拆箱
表示在可行的情况下被使用以降低开销;装箱表示被用于与需要引用类型的API的互操作
性。与例如Java中现有的原生包装器不同,装箱表示可以从值类型的描述自动生成。例如,
每个值类型可以使用类文件来定义,并且虚拟机104使用该类文件来自动生成表示用于值
类型的箱对象的新的类文件。作为另一示例,源代码文件101中定义的值类型由编译器102
编译为用于值类型的分开的类文件和值类型的装箱形式。作为又一示例,值类型和值类型
的装箱形式这二者可以共享同一类文件,但是虚拟机将取决于上下文以不同方式?#28304;?#20540;类
型的使用。

行为。在一些实施例中,值类型不仅仅是数据的元组;它们还可以以方法的形式定
义行为。例如,复数值类型的定义可以定义用于执行复数运算的方法。然后如果硬件原生是
可用的(?#28909;?#23545;于128位的数值),则虚拟机104可以选择内部化该行为。类似地,数据结构游
标可以定义工厂方法和访问方法,同时保持其成分值被安全地封装。诸如Java中的
toString和equals之类的实用程序方法(utility method)可以被强加于值类,但不一定如
此。在一些实施例中,实用程序方法能够逐个值类型地定制。

名称。诸如JVM类型?#20302;持?#31867;的一些类型?#20302;臣负?#20840;部是标称的(nominal),而不
是结构的。类似地,在一些实施例中,值类型的成分可以通过名称识别,而不是仅通过元素
号识别。(这使得值类型更像记?#32423;?#19981;是元组)。

互操作性。在诸如JVM之类的一些虚拟机中,存在针对具有值对应物的泛型对象的
若干操作,诸如equals、hashCode和toString。在一些实施例中,虚拟机(在缺乏来自值类型
的作者的指令的情况下)按成分实现这些方法。除了对象(Object)之外,诸如Comparable
(可比较型)之类的其他类型还可以与合适的值类型互操作,从而向诸如TreeSet<
UnsignedInteger>之类的类型打开大门。

封装性。在一些实施例中,值类型具有?#25509;?#25104;分,正如对象具有?#25509;?#23383;段。这使得
例如安全的外部(foreign)“指针”或游标成为可能。值类型可以被配置为阻?#39592;?#22312;的攻击
者通过提取?#25509;?#25104;分或通过合法操作的勉强组合造出非法值来摧毁封装性。

可验证性。在一些实施例中,虚拟机104的指令集中的对于值类型的支持是能够被
验证器106验证的。

变量。在一些实施例中,诸如字段、数组元素、局部变量和方法参数之类的变量类
型都被配置为保持值类型。此外,方法被配置为返回值类型。此外,修饰符(诸如Java中的
final和volatile)可以被应用于值类型以实现它们的常规效果。

数组。在一些实施例中,值类型的数组被打包(packed),非间接地、类似于原生的
数组。这不一定意味着数组本身被打包在其他对象内部。因此,数组可以保持值类型元素的
扁平化表示,但是如果数组是对象的字段,则对象可以存储可被分配在堆302上的数组的指
针。

扁平化。值类型提供了用于表达具有较少指针间接的数据结构的自然方式。因此,
使用值类型来使数据扁平化允许虚拟机104更高效地布置一些数据结构。

3.3示例性限制

由于值类型不具有标识,因此存在某些操作,一些实施例可以选择不允许对值类
型进行这些操作或者为这些操作分配新的含义以供在值类型的背景下使用。在一些实施例
中,对值类型的限制在虚拟机104中被实现为供验证器106遵循的附加规则。因此,如果类内
的方法包含违背规则的代码,则生成异常或错误。以下是一些示例:

锁定。为了支?#31181;?#22914;在Java语言中执行的同步,对象有时被用作经同步的语句的
锁对象。在一些实施例中,由于缺乏对于该特征所期待的头部信息,因此虚拟机104不允许
针对这些语句使用值类型。此外,在一些实施例中,虚拟机104不允许针对值类型调用与同
?#36739;?#20851;的方法。例如,Java中的wait(等待)和notify(通知)方法。

标识比较。(在Java中)针对对象的“=?#20581;?#25805;作符执行标识比较,但是针对原生,该
操作符执行按位比较。由于值类型不一定具有指针,因此该操作符不适用于值类型。在一些
实施例中,通过递归地执行“=?#20581;?#25805;作(最终基于较低级别的对象/原生来评估)、调用
equals方法和/或执行按位比较来执行解释针对值类型的诸如“=?#20581;?#20043;类的操作符。

标识散列码。诸如经由Java中的System.identityHashCode之类的用于对象的基
于标识的散列码不适用于值类型。做出对象的基于标识的区?#20540;摹?#20687;序列化那样的内部操
作要么不适用于值类型(由于它们不适用于原生),要么会使用由值类型定义的单独的散列
码方法供应的基于值的区分。例如,按成?#20540;纳?#21015;计算可以被还原为默认。然而,当值类型
的成分是?#25509;?#30340;时,这可能泄露可?#36824;?#20987;使用的信息。

克隆。在一些实施例中,虚拟机104将诸如Java中的Clone方法之类的克隆解释为
对于值类型的标识转变。

终止化(finalization)。在一些实施例中,对于值类型的终止化是不允许的,因此
在许多实施例中对值类型的终止化将没有用处(但是值类型可以保持自身可终止化的引用
类型的成分)。

以上限制中的许多限制对应于Java中针对所谓的基于值的类的限制。实际上,在
实施例中,每个值类型的装箱形式是基于值的类。

在一些实施例中,虚拟机104对值类型做出“软”限制以确保值类型在存储空间和/
或成分数量方面不会“太大”。由于值类型通过值来传递,因此随着成分数量增加,复制许多
成?#20540;?#24320;销越来越可能压倒通过移除指针和对象头部的开销而获得的任何节省。由于类对
象是使用指针通过引用来传递,因此大组的成分值可以可替代地使用类来建模。

在一些实施例中,值类型的精心构思的使用通过省略对象指针和头部以及定期通
过值传递成分来获得性能?#36879;?#26434;度的益处。具有少量成?#20540;?#20540;类型通常整齐地匹配大多数
当前的中央处理单元(CPU)(其对寄存器文件的尺寸具有相对较小的限制)的能力。当超过
这些限制时,一些实施例中的虚拟机104具有将值类型分散到栈(诸如虚拟机栈310/313)
和/或所管理的堆302存储器上的灵活性。

在一些实施例中,取决于值类型的尺寸和/或值类型是否在不能被修改的容器中,
虚拟机104在通过值传递值类型或通过引用传递值类型之间切换。在后面的节中以更多细
节探索该特征。

3.4指针管理

当使用值类型的扁平化表示时,值类型不被指针访问或者这种指针在虚拟机104
实现内对用户隐藏。因此,即使虚拟机104在底层使用指针,虚拟机104也确保从用户的视角
来看值类型遵循通过值传递的行为。在一些实施例中,某些附加操作也是虚拟机104不允许
的或者被虚拟机104分配新的含义。

空值(null)。空值是每个引用类型的?#34892;?#20540;,其意味着“没有实例”。然而,在值类
型的背景下,空值可能是不适用的,这与在大多数语言中空值通常不适用于原生大致相同。
因此,在一些实施例中,对于值类型来说被指派为空值以及与空值相比较是不允许的。然
而,该限制将不适用于值类型的装箱形式,其中将值类型装箱的容器对象可以保持空值并
且可以与空值相比较。

副作用。尽管包含整个值的变量可以被重新指派为不同的值,但是值的单独部分
通常不受到分段的副作用的影响,就好像它们通过对于该值的指针被访问一样。因此,整数
可以从2被更新到3,但是在一些实施例中用户被限制为整个值指派。结果,不向用户提供可
以改变2的最低位以将该值改变为3的代码指令。诸如Java之类的某些语言在该方向上给出
的是像intval|=1一样的复合指派操作。此外,在第一变量处将值从2改变为3不会导致其
他地方的第二变量变成3(当两个变量都指向值被改变的同一存储器位置时会出?#25191;?#24773;
况)。结果,在一些实施例中,(从用户的角度来看)虚拟机104阻止了分段的副作用。然而,尽
管从用户的视角来看,值类型看上去是作为整体被替换(作为不可变性的性质)并且不会导
致对于其他变量的副作用(作为扁平性的性质),但是在一些实施例中在底?#38408;?#25311;机104可
以执行违背该性质的优化。例如,尽管在语义上代码表?#20540;?#23601;像Point A被Point B完整地
替换一样,但是在底层,虚拟机104可以仅替换不同的成分以作为优化的形式。作为另一示
例,假如在语义上虚拟机104诸如通过仅在值类型不能改变的(例如,值类型是最终的)情况
下执行该优化来阻止副作用,则在值类型较大的情况中,指针可以被用于最小化复制开销。

在一些实施例中,语言允许通过指针访问值类型,多达并且包括成分变化。在这种
实施例中,该概念的复杂度协助?#38236;?#25968;据结构以及虚拟机104数据。

引用转换。在一些实施例中,像原生类型那样,值类型可以被装箱以便被用作引
用。因此,在一些实施例中,虚拟机104具有用于隐式地对值类型进行装箱和拆箱的规则,类
似于Java当前怎样执行用于原生值的装箱和拆箱。例如,通过基于上下文在整型和相应的
Integer(整数)值类之间自动转换。

指针多态性。在一些实施例中,对象并入运行时类型信息,方法可以是虚拟的,类
型可以在运行时被测试,以及(许多)静态引用类型可以在运行时指向一系列具体的子类。
在这种实施例中,由于指针变量尽管具有固定的尺寸但是可以指代任何尺寸和类型的数
据,因此前面提到的特征起作用。由于值类型没?#22411;?#37096;来承载类型信息并?#20918;?#35774;计为被扁
平化到它们的包含对象中,因此值类型(在一些实施例中)不能被动态地类型测试并且不能
具有可变的尺寸。结果,在一些实施例中,虚拟机104阻止子类化(sub-classing),因为该特
征对于值类型没什么用处。然而,诸如Java中的Comparable接口之类的抽象的超类和接口
仍然可以被使用,因为这些结构体不能被分开实例化。在一些实施例中,值类型实现头部信
息的缩减集合,而不是没?#22411;?#37096;信息,诸如包括尺寸数据以支持可变尺寸,但是不包括用于
实现标识特征的诸如标识号(例如,对象的存储器地址)之类的其他信息。

反射(reflection)。作为指针多态性的极端情况,在诸如Java之类的语言中,任何
对象可以被转换为顶级类型Object并且可以针?#36816;?#30340;?#22336;?#20018;表示、它的类、它的字段和字
段值的集?#31995;?#31561;而被检查。由于在一些实施例中值类型不支持超类,因此虚拟机104可以禁
用转换值类型并且因此还禁用反射。然而,在一些实施例中,值类型的方法可以包括创建与
从Object类型生成的?#22336;?#20018;表示类似的?#22336;?#20018;表示的方法。

原?#26377;浴?#25351;针提供了到其对象(可以原子地改变)的访?#20107;?#24452;。因此,竞争的线程观
察到旧对象或新对象,而不是二者的混合。相比之下,多字段值可能经受数据竞争的,在数
据竞争中竞争的线程可能观察到新字段值?#36884;?#23383;段值的混合。在当前的语言中,在长整型
和双精度型类型的情况下该“结构撕?#36873;?#38382;题有时可以作为极端情况?#36824;?#23519;到,但是在值类
型的情况下该问题更加急迫,因为它可以?#29616;?#22320;损害封装性。在一些实施例中,虚拟机104
在类型使用位置和类型定义位置这二者处按照请求供应原?#26377;浴?#36825;类似于诸如Java之类的
语言在在长整型和双精度型变量被声明为易变的情况下如何在类型使用?#38236;?#22788;按照请求
供应原?#26377;浴?#22312;当前硬件中保证原?#26377;?#30340;成本足够大以致于对于不要求原?#26377;?#25110;仅要求某
些变量具有原?#26377;?#30340;程序,始?#25214;?#27714;原?#26377;?#21487;能导致大量不必要的开销。精确的折衷跨平
台变化。

3.5示例性定义

在一些实施例中,值类型的一些特性是类常见的:一批经命名的、类型成分(字
段)、行为(方法)、隐私(访问控制)、编程初始化(构造器)?#21462;?#22240;此,在一些实施例中,使用特
殊标记的类文件来定义值类型。然而,虚拟机104可以经由验证器106对这些类文件施加特
殊的规则,诸如在先前的节中所描述的限制。类似地,用于值类型的语法元素可以被精心设
计以便看上去类似于源语言中的写类。

在诸如Java之类的一些语言中,存在采取该方法的先例,诸如使用类文件103来表
示接口,因为这些接口还与普通类有相似之处。除了模式位和小语法的附加之外,在一些实
施例中,接口的二进制可以与适当的类的二进制相同,除了接口具有附加的语法和语义限
制。类似地,值类型可以在源代码文件101中定义并且使用语法的小改变来写,但是具有由
验证器106应用于所得到的类文件103的附加限制。

通过使用示例性语法,之前提供的Point示例可以被重写为如下的值类型:


上面的示例和引用等价物之间的语法区别从将结构体标记为值类型而不是适当
的类的关键字_ByValue开始。然而,这仅是示例性的语法,将结构体标记为值类型的任何方
式是容许的,诸如通过关键字、符号或任何其他语法来标记。此外,诸如字段、结构体和/或
方法之类的用于源语言的相同的编码惯用语法可以被重复使用以将这些值/行为添加到值
类型的定义。在一些实施例中,如果用户在源代码文件101中未提供实用程序方法(并且语
言允许该省略),虚拟机104或编译器102填补某些实用方法(诸如按成?#20540;膆ashCode、
equals或toString)。

如果另一个类声明类型Point的字段,则虚拟机104将分配用于在托管对象中的x
和y成?#20540;?#23384;储,而不是对Point箱的引用。这可以被视为对象内联或扁平化。类似地,Point
的数组将被布局为交替的x和y值的经打包的数组,而不是?#28304;?#20648;x和y值对的容器的一系列
引用。

在一些实施例中,由于与类相似地使用特征和语法来向用户暴露值类型,因此值
类型的定义对于源语言的程序员来说立刻是清楚的。然而,在各种实施例中不适用于值类
型的一些熟悉的特征(诸如Java中的extends或protected)可能是不适用的。因此,如果用
户尝试在值类型的定义中包括这些属性,则虚拟机104的编译器102或验证器106抛出异常
或生成错误。

在一些实施例中,源语言已经具有表达限制的关键字或其他机制,诸如子字段在
构造之后的不可变性。例如,Java中的final关键字。因此,如果用户不再使用final关键字,
则编译器102可以提供解释该关键字必需的错误或者隐式地将关键字添加到所生成的类文
件。此外,在一些实施例中,如果final属性丢失,则虚拟机104隐式地将final属性添加到所
生成的类文件,或者将该属性当作已经被设置。

3.6示例性用法

前一节描述了值类型可以如何以与类相同的方式编码,因此下一个问题是在虚拟
机104中如何定义行为以提供好像值类型是原生那样的?#28304;?#19979;面是Point类的一些示例性
使用:



在这些示例中,Point可以是字段、参数、局部变量或者返回值。在所有这些情况
中,在一些实施例中虚拟机104将Point的成分放置在独立地管理的位置中,诸如机器寄存
器。displace方法返回新的Point值。在一些实施例中,虚拟机104通过值而不是通过(不可
见的)引用来返回Point。

在一些实施例中,像原生那样,值类型可以引导重载。这里是与上面兼容的用于
stringValueOf的一些重载:


使用Java作为示例,值类型的以上用法在若干方面不同于原生。

第一,用于成员选择的点语法适用于值类型,如p.x或p.equals。诸如Java之类的
一些语言中的原生根本不支?#20540;?#35821;法。在一些实施例中,使用值类型来替换或补充表示原
生的值类(诸如整数(Integer)),从而为针对在一些情况中是标准原生的类型(诸如整型、
浮点型、双精度型等)应用方法打开大门。

第二,在一些实施例中,虚拟机104不提供对于诸如Point之类的由用户定义的值
类型的文本的支持。替代地,定义的构造函数被调用以设置成?#20540;?#20540;。在一些实施例中,为
了确保封装性,按成?#20540;?#20540;创建除非由合适的构造函数提供,否则不被虚拟机104允许。上
面的示例使用关键字__MakeValue来标记上面的两个位置:新的Point值被创建的位置以及
这种构造函数被调用的位置。然而,替代的语法还可以被用于表示值类型构造函数,诸如
“new Point”、“Point?#24065;?#21450;空?#22336;?#20018;。类似地,一些实施例不提供对于用于值类型的编译时
常量的支持。在其他实施例中,虚拟机104提供对于用户定义的文本和常量表达式的支持。
因此,在一些实施例中从被执行以建立常量表达式的编译时代码构建用户定义的操作符。

第三,用于诸如Java之类的一些语言的内置操作符是利用原生工作的主要方式,
但是在一些实施例中这些内置操作符不适用于Point。然而,用户定义的操作符可以被用于
提供功能等价物。一些例外可能是作用于每个种类的值的操作符,诸如关系操作符(==
和!=)和?#22336;?#20018;串接(+)。?#22336;?#20018;串接可能是棘?#20540;模?#22240;为在一些实施例中?#22336;?#20018;串接在值
类型驻留的类和原生类型之间的区分处被精确地精妙地重载。例如,如许多Java程序员通
过?#28304;?#27861;(trial and error)发?#20540;模?#34920;达式("a"+1)+2和"a"+(1+2)具有不同的结果,因为
第一个表达式首先转换为?#22336;?#20018;从而形成“a12?#20445;?#32780;第二个表达式在加法后转换为?#22336;?#20018;
从而形成“a3”。

在一些实施例中,关系操作符被当作用于?#26800;?#26041;法(类似于Java中的equals)的别
名。另外,低级别的按位?#26800;?#26159;另一种候选方法。然而,在一些实施例中,关系操作符可以潜
在地导致值类型的装箱形式和拆箱形式之间的行为差异,使用Java作为示例如下所示:

Point p1=__MakeValue(0,1);

Point p2=__MakeValue(1,0);

Point p3=__MakeValue(1,0);

assert(!p1.equals(p2));//值?#26800;?br />

assert(p1!=p2);//再次值?#26800;?br />

assert(p2.equals(p3)&&p2==p3);

Object box1=p1,box2=p2,box3=p3;//将它们装箱

assert(box1==box1);//x==x总成立(除了NaN(非数字))

assert(!box1.equals(box2));//Object.equals调用Point.equals

assert(box1!=box2);//还必须是

assert(box2.equals(box3));

if(box2==box3)println("the cat died");//不确定

assert((Point)box2==(Point)box3);//返回到Point.equals

if(box2==(Object)p2)println("the cat died");//不确定

利用小调整,在Java中上面所有的测试可以在整型和整数(Integer)的情况下被
重现。然而,对于一些小的整数值,由于Integer.valueOf工厂方法的特点而非原生、值类型
或箱的内在特征,猫不会存活。

第?#27169;?#23613;管原生不具有对应于?#25214;?#29992;的值,但是原生具有一般是零的默认值。该默
认值在未初始化的字段和数组元素的初始内容中出现。因此可以为每个值类型指定默认
值。例如,一种?#38469;?#26159;将复合值设置为在其所有子字段中是递归默认的。假如预定义的默认
值在诸如Java之类的一些语言中是固定值,则该约定适用于许多语?#21592;?#26223;。

在一些实施例中,即?#26500;?#36896;函数从未创建默认(全零位)的值类型,值类型定义中
的方法的作者也可以向默认的值类型提供行为,因为这些值类型在一些未初始化的变量中
可以?#36824;?#23519;到。在实施例中,虚拟机104要么禁止无参数的构造函数要么要求它们产生默认
值,以便于避免“决斗的默认值”。

在一些实施例中,作为替代,虚拟机104通过强制包括公有的空构造函数来迫使显
式地构造默认值,像这样:public Point(){x=0;y=0;}。在公有的空构造函数中,所有子
字段被初始化为默认值,否则编译器102和/或验证器106将报告错误。可替代地,虚拟机104
可以不允许空构造函数,并且为默认值保留其含义。

在一些实施例中,作为替代,虚拟机104允许通过?#21592;?#20934;类定义施加的模式或语法
来指定更精心制定的默认值。然而,?#28304;?#23384;在三点考虑:(1)在一些情况中默认值将要求特
殊的扩展而不是简单的限制,(2)在一些情况中默认值将包括特殊的规则以在来自空构造
函数的副作用的情况下编码,以及(3)相比于全零位的约定,在运行时应用由用户指定的默
认值可能潜在地具有更高的成本。

3.7示例性实现?#38468;?br />

在一些情况中,类的某些特征对于用于特定实施例的值类型将没有意义。下文以
问题和回答的格式表示根据特定实施例的用于值类型的设计和/或实现决策。然而,下文所
描述的回答不是决定性的;其他实施例可以提供对下文所呈?#20540;?#38382;题的不同回答。因此,其
他实施例对于每个问题可能有所不同。在一些实施例中,本节中所描述的关于值类型的限
制在虚拟机104中被实现为供验证器106遵循的附加规则。

子类型化(subtyping)

值类可以扩展引用类类型吗?在大多数情况中,不可以。

引用类可以扩展值类型吗?在大多数情况中,不可以。

具体的值类可以扩展另一值类型吗?在大多数情况中,不可以。(因为具体的值类
是最终的。)

值类型定义可以是抽象的或非最终的吗?在大多数情况中,不可以。

值类型定义可以实现接口吗?可以。当我们将值类看作接口实例时,装箱可以发
生。

值类型可以参与基于继承的子类型化吗?在大多数情况中,不可以。(就像原生那
样。)

是否存在用于值的根类型(诸如Java中的Object超类型)?不一定。在一些实施例
中,值类型的超类型可以被实现为模板化机制。

包含

值类型可以包含引用类型的字段吗?可以。

引用类可以包含值类型的字段吗?可以。

值类型可以包含值类型的成分字段吗?可以。

数组可以包含值类型的元素吗?可以。(在一些语言中,数组是对象的类型)。

值类型可以包含数组类型的字段吗?可以。(例如,当数组是对象时)。

值类型可以包含非最终字段吗?在许多实施例中,不可以,但是其他实施例可以允
许具有非最终字段的值类型。

值类型的所有字段都必须是递归不变的吗?不一定。(递归不变性是类型的独立特
征)。

值类型可以具有成员类型吗?可以。(非静态成员类型具有记录包含值的隐藏字
段)。

值类型可以是成员类型吗?可以(如果它们是非静态的,则它们具有指向包含对象
的隐藏字段。)

当创建值类型的数组时,初始元素是什么?它们都是默认的全零位值。(就像原生
那样。)

其类型是值类型的字段的初始值是什么?默认的全零位值,直至第一次指派或初
始化。

其类型是值类型的局部变量的初始值是什么?看情况,在一些实施例中指派规则
禁?#26500;?#23519;这样的值,直至第一次指派。

值类型可以包含其自身类型的字段吗?在大多数情况中,直接地或间接地都不可
以(类似于一些语言中的现有限制:类不能将其自身作为子类)。

兼容性

值类型是对象吗?不一定,尽管值类型可以被装箱成对象。

原生是值类型吗?可能是。(值类型命名的整型、?#32423;?#22411;等将向包装器类提供良好
的继承者,就像它们存在于诸如Java之类的当前语言中那样。)

值类型的数组是否为协变的?在大多数情况中,不是。(就像原生那样,值类型箱的
数组是协变的)。

值类型是否参与隐式转换?在大多数情况中,不参与。(在一些实施例中,虚拟机
104不需要实现隐式转换,诸如Java中的int toUnsignedInteger)。

每个值类型都定义了类似对象的方法(toString等)吗?有时是。在一些实施例中,
虚拟机104需要类似对象的方法以使得它们的装箱形式可以与期待对象而不是值类型的现
有API互操作。然而,不是在所有实施例中都需要类似对象的方法。

是否存在用于这些方法的默认的按成?#20540;?#23454;现?是的。例如,用于箱的根类型是用
来放置默认的按成?#20540;?#20195;码的逻辑位置。

值类型可以被序列化吗?看情况。在一些实施例中,为了阻止违背封装性,虚拟机
104不实现用于值类型的序列化。然而,在其他实施例中,虚拟机104可以实现用于值类型的
序列化。

值类型的用户可以请求原?#26377;?#21527;?可以。在一些实施例中,可以使用诸如关键字
volatile或_AlwaysAtomic之类的关键?#31181;?#23450;原?#26377;浴?br />

当将值类型指派给泛型对象时发生了什么?虚拟机104基于值类型的类文件自动
将值类型装箱到虚拟机104生成的类中。生成的类文件反映值类型的字段和方法,但是生成
的对象包含头部信息并且因此可以被用于标识以及被用于与期待对象的API的互操作性。

当空值被分配给值类型(或者与值类型相比较)时发生了什么?如果该值类型是装
箱的,则引用比较将返回不相等;如果值类型是拆箱的,则抛出异常。

封装性

值类型可以具有非公有的字段吗?可以。

值类型可以具有非公有的方法吗?可以。

值类型可以具有静态方法或字段吗?可以。

值类型是怎样构造的?#23458;?#36807;调用构造函数。值类型构造函数事实上是工厂方法,因
此(使用JVM?#32440;?#30721;作为示例)在?#32440;?#30721;中不存在new;dup;init跳跃(dance)。

值类型的定义者可以要求其所有成分值的原?#26377;?#21527;?可以。例如,通过在值类型定
义中使用关键字或符号,这些关键字或符号指示操作将始终是原子的。

值类型的封装性可以被布置为排除所有默认的按成?#20540;?#25805;作吗?可以。(例如,通
过重载相关方法)。

值类型可以在不要求客户机重新编译的情况下改变尺寸或布局吗?可以。

值类型的封装性可以被布置为排除其所有字段是零的值吗?在大多数情况中,不
可以。(如上文所指出的,这是慎重的妥协。如上文所指出的,一些实施例中的默认值可以与
无参数的构造函数值一致。)

诸如?#32440;?#30721;之类的虚拟机指令可以以访问值类型的?#25509;?#23383;段的方式被使用吗?取
决于实施例。

其他?#38468;?br />

是否存在对值类型的复杂度的限制?是的。在一些实施例中,虚拟机104对值类型
的成?#20540;?#25968;量和/或尺寸施加限制以便于做出性能保证。例如,但是不足够低以做出性能保
证。例如,值类型可以被限制为诸如255?#31181;?#31867;的阈值。

虚拟机104支持通过拆分超类来重构值类型吗?在大多数情况中,不支持,除非虚
拟机104允许抽象的值类型。

虚拟机104支持将方法重构到值类型中或从值类型中将方法重构出来吗?支持,例
如,与默认方法的公共接口可以被用于该目的。

虚拟机104支持对于装箱的值调用值类型的方法吗?支持。在一些实施例中,虚拟
机104自动对值进行装箱和拆箱以创建用于API的桥。例如,当使用Point时,取决于上下文
和环?#24120;?#35813;表示将有时为值类型,有时为箱引用类型。

在一些实施例中,虚拟机104禁止值类型的子类化和子类型化以避免指针多态性。
抽象超类型(?#28909;鏙ava中的接口Comparable)可以被考虑,因为它们不能被实例化。结果,虚
拟机104可以因此确保所有方法以方法接收者的确切类型被明确地解析。在一些情况中,该
决策还回避了值类型数组的问题,如果数组可以包含(例如)2字段Point和3字段
ColoredPoint(?#26087;?#28857;)值,则值类型数组可以包括尺寸可变的元素。对于数组,由于原生数
组已经具?#22411;?#20840;同构的元素,因此?#35272;?#21407;生语义是方便的。然而,该方法不是没有问题。例
如,对于实现Comparable的值类型Bignum,虚拟机104可以允许箱的数组Bignum.__
BoxedValue[]是接口数组Comparable[]的子类型,但是在一些实施例中扁平的数组类型
Bignum[]不能也是Comparable[]的子类型。

3.8示例性?#32440;?#30721;和类型描述符

存在可以在虚拟机104的指令集(例如,?#32440;?#30721;)中显现值类型的许多方式。例如,
用于值类型的全新指令可以通过将值类型当作全新的结构体或者重载现有指令以接受值
类型或引用来实现。本节关注可以被实现为生成、加载、存储和/或以其他方式操纵值类型
的新指令。然而,如上文提到的,其他实施例可以重载现有指令以实现类似的效果。

建立在上面“示例性类文件结构”中所?#33268;?#30340;描述符示例上,存在用于原生的单字
母类型描述符(例如,用于整型的I)、用于类的“L”描述符(例如,L ClassName),并且对于任
何类型,可以通过追加“[”来为该类型的数组导出类型描述符。在实施例中,为值类型添加
另一形式;用于值类型com.foo.Bar的类型描述符将会是Q com/foo/Bar;这就像用于引用
类型的“L”描述符一样,除了不同的符号“Q”。例如,考虑以下方法:

public static double getR(Point p){...}

用于以上方法的签名将会是(Q Point)D,这指示它采用值类型Point的单个参数
并且返回双精度型。

新虚拟机104指令的示例以如下格式描述:

//描述

opcode[constant pool operands]stack operands->stack result

在一些实施例中,对于所有操作码,“qdesc”是用于值类型的Q描述符。然而,对于
许多指令,验证器106可以从指令的上下文推断描述符。因此,如果这样的描述符可以替代
地通过上下文来推断,则一些实施例可以选择忽略来自指令的这种描述符。用于局部变量
401的表槽(slot)和用于操作数栈402的表槽可以保持值类型以及原生或引用。

在一些实施例中,值类型消耗局部变量401和/或操作数栈402中的单个槽。因此,
每个槽不必具有固定长度的尺寸。然而,在其他实施例中,值类型消耗多个槽,类似于在一
些JVM实?#31181;?#35832;如双精度型之类的尺寸过大的原生类型如何被设计为占用两个槽而不是一
个槽,从而使得槽可以具有相等的尺寸。在一些实施例中,虚拟机104可以在不重新编译代
码的情况下改变槽的尺寸和布局。后面的节中?#33268;?#20851;于虚拟机存储器布局300内的值类型
的存储的附加?#38468;凇?br />

在实施例中,为了操纵栈帧400上的值类型,虚拟机104支持以下指令。同样,尽管
以下示例中的一些形式可以认为是不必要的,但是示例顾及到明确性和完整性。因此,在一
些实施例中,新指令的数量可以远小于下文所描述的新指令的数量。

//从局部变量加载值类型

vload[qdesc?,index]->value type

//将值类型存储到局部变量中

vstore[qdesc?,index]value type->

//创建值类型的新数组

vnewarray[qdesc]size->arrayref

//将值类型存储到数组中

vastore[qdesc?]arrayref,index,value type->

//从数组加载值类型

vaload[qdesc?]arrayref,index->value type

//提取来自值的成分

vgetfield[field-desc]value type->result

//将成分插入到值类型中(为了构造函数的?#25509;?#20351;用)

vputfield[field-desc]value argument->value type

//构建具有全部默认的成?#20540;?#26032;生值类型(为了构造函数的使用)

vnew[qdesc]->value type

//对值类型调用方法

vinvoke[method-desc]value type,(argument)*->(return)?

//返回值类型

vreturn[qdesc?]value type

在一些实施例中,虚拟机104支持可以对任何类型的帧400内容操作的若干“多态
的”指令,诸如JVM?#32440;?#30721;集中的“dup?#20445;?#36825;些指令可以被扩展为同样支持值类型。在大多数
情况中,这些多态指令可以用最少的努力被重载到现有指令上。使用JVM指令码集作为示
例,vinvoke功能可以被重载到invokestatic上,而vgetfield功能可以被重载到getfield
上。

在一些实施例中,上文提到的字段和方法描述符将会是常量表201引用,诸如指代
方法引用结构207、字?#25105;?#29992;类型206和/或类信息结构203的引用。在一些实施例中,描述符
的成分通过值类型的标称名称(例如,没有任何“Q”前缀)指代值类型。对应类的装箱形式具
有例如?#29992;?#36848;符语言(例如,L Foo)导出的它们自己的?#32440;?#30721;名称。在一些实施例中,虚拟
机104支持克隆常量表201类型,诸如CONSTANT_ValueMethodref,使用Java类文件作为示
例。

在一些实施例中,值类型中的静态方法重复使用为适当的类实?#20540;?#30456;同指令,而
不需要特别指向到值类型的特殊指令。例如,使用JVM?#32440;?#30721;集作为示例,可以使用
invokestatic来调用值类型中的静态方法。在一些实施例中,类似于静态方法,静态字段可
以重复使用由虚拟机104实?#20540;?#29992;于操纵静态字段的相同指令来操纵适当类的静态字段。

在一些实施例中,虚拟机104阻?#26500;?#36896;函数调用通过引用传递要构造的值类型。替
代地,值类型构造函数被实现为将作为静态方法被调用的静态工厂方法。用于成分初始化
的各变化步骤通过特权指令vputfield的使用而被内部地呈?#25351;?#26500;造函数,该特权指令
vputfield与为用于初始化属性对象的最终字段的构造函数保留的特殊指令(诸如JVM?#32440;?br />码中的putfield)等效地操作。要注意vputfield返回更新后的值,因此不存在副作用发生
的机会。

在一些实施例中,虚拟机104将如构造函数使用的vnew和vputfield操作符的效果
结合到vpack指令中,vpack指令将会采用栈上的一系列成分。这些成?#20540;?#39034;序和类型将由
包含值类型定义隐式地定义。这将使得一些简单的构造函数稍微更加紧凑,但是可能导致
虚拟机104中实?#20540;?#25351;令及其包含类之间的新型耦合。在一些实施例中,虚拟机104对作为
命名字段的簇(cluster)的复合类型进行操作,而不是对入栈的值的?#34892;?#20803;组进行操作。在
一些情况中,如果每个字段初始化具有其自己的vputfield操作码,则虚拟机104指令和源
代码之间的对应关系可以更易于追踪。

在一些实施例中,当从较高级别的指令生成较低级别的指令时,改变某个值类型
的值内的字段的一个或多个较高级别的指令可以被识别。该值可以是例如潜在地具有多个
不同的成分字段的值类型的实例。本文描述了这种值类型的示例,诸如点(Point)或复数
(Complex)。可以确定的是,在较低级别的指令的上下文中,用于该值的至少一个成分字段
的数据将被集体存储在单个容器内。例如,字段可以被存储为其对应的子值的拆箱表示,而
不是?#28304;?#20648;相应子值的其他容器(多个容器)的引用。响应于该确定,生成单个较低级别的
指令。这种较低级别的指令的一个示例是本文所描述的vputfield指令。

在一些实施例中,所生成的单个较低级别的指令被配置为命令解释器108识别与
字段对应的容器的一部分,诸如一个或多个位。单个较低级别的指令还被配置为命令解释
器108根据一个或多个较高级别的指令来改变该部分。识别和/或改变可以至少部分基于与
值的值类型相关联的元数据。例如,指令可以使得解释器108使用用于值类型的字段定义来
定位该部分和/或实行用于对应的值类型定义的访问控制信息、类型检查等?#21462;?#22312;实施例
中,单个较低级别的指令命令解释器108在不使用指针定位字段的情况下和/或在不必发出
使值开放到其成分字段中的分开指令的情况下进行该操作。

在实施例中,可选择性地通过重新排序、合并或分开彼此相关并且与可以读或写
存储在容器中的值或容器的至少一些成分字段的任何其他指令相关的两个或更多个这种
较低级别的指令的效果来生成较低级别的指令。这种效果的重新排序、合并或分开可以受
保护存储在容器中的值的每个成分字段以及存储在容器中作为整体的值的一致性的规则
影响。因此,?#38469;?#21487;以包括使用分层的数据结构的?#30701;状?#20648;器模型,当对象拆分成值时,其
可以拆分成更小的值并?#26131;?#32456;一直向下拆分成成分原生和引用。

根据实施例,一种方法包括:当解释诸如Java?#32440;?#30721;之类的指令时,识别指令以将
第一个较小的值作为第二个较大的值的字段插入。该指令可以是例如单个较低级别的指
令,诸如上面生成的指令。第二个值可以是例如具有集体存储在容器中的多个不同成分字
段的经定义的值类型的值。第一个值可以是例如对应于字段的子值。在实施例中,确定第二
个值具有某个值类型。基于与某个值类型相关联的元数据,对应于字段的第二个值的一部
分被定位,并?#19994;?#19968;个值被加载到该部?#31181;小?#36825;可以包括例如基于与某个值类型相关联的
值类型定义数据来实行访问控制信息和类型检查,和/或使用值类型定义数据来定位相关
部分。在实施例中,选择性地通过重新排序、合并或分开两个或更多个这种较低级别的指令
的效果来生成较低级别的指令,诸如上文所描述的。

3.9装箱和对象互操作性

在实施例中,每个值类型具有对应的箱类,就像在Java中Integer是用于整型的箱
类型。在一些实施例中,虚拟机104或编译器102从用于值类型的类文件中所提供的定义自
动导出用于值类型的箱类的类文件(或者反之亦然),而不是要求值类型及其对应的箱的分
开编码。例如,方法和字段可以从值类的类文件得到,但是其中箱类文件包含标识符,该标
识符指示虚拟机104应当将箱类文件解释为指代适当的对象类。箱类文件还可以包含可以
不存在于值类型的类文件中的附加的元数据,诸如超类(例如,Java中的Object超类)的存
在。可替代地,虚拟机104可以生成对于值类型和箱表示这二者通用的一个类文件,其中类
文件取决于上下文而被虚拟机104不同地处理。例如,如果值类型使用描述符“Q Foo?#20445;?#21017;用
于对应的箱类的描述符可以是“L Foo”。对于这两种类型,虚拟机104将知道寻?#20918;?#31216;为Foo
的类文件并?#19968;?#20110;哪个描述符被使用来生成值视图或引用视图。

在一些实施例中,诸如构建之类的公共操作具有用于值类型或箱类的不同机制。
例如,编译器102可以生成多个版本的类工件(class artifact)(例如,具有签名(...)V的
标准构造函数?#36884;?#26377;签名(...)Q Foo的值构造函数)或者虚拟机104将根据需要从其中一
个的指令导出另一个。在一些实施例中,对于值类型Foo,Foo可以被写为指代值形式,而
Foo.__BoxedValue被写为指代Foo的装箱形式。

在实施例中,值类型的装箱表示和拆箱表示之间的转换像诸如Java之类的一些语
言中当前的原生箱(例如,valueOf(boxed))那样通过遵循命名约定的方法来表示,或者可
以?#19978;?#19979;面的转换指令来表示:

//将值装箱

v2a[qdesc]value->ref

//将值拆箱

a2v[qdesc]ref->value

值之间的比较(类似于JVM?#32440;?#30721;集中的acmp和icmp?#32440;?#30721;)也可以由遵循命名转
换的方法来表示,或者用像下面的特殊指令来表示:

//使用按成?#20540;摹?#25353;位的以及引用?#26800;?#26469;比较两个值

vcmp[qdesc?]value,value->boolean

在一些实施例中,尽管在一些情况中像操纵原生和引用的指令那样处理新的值类
型指令的“克隆”是有用的,但是在实施例中转换和比较指令可以使用方法调用(例如,
vinvoke)来实现。

在一些实施例中,像数组那样,箱类由虚拟机104生成。在实施例中,?#20302;?#23558;箱代码
尽量多地分解为常见的抽象超类。在Java中,这大约是为经典对象采取的方法,其中默认行
为在java.lang.Object中找到。

3.10示例性代码

示例:构造

在本节中使用上面在“新?#32440;?#30721;和类型描述符”中介绍的新指令与来自JVM?#32440;?#30721;
集的指令的组合来描述创建和使用值类型的示例。尽管JVM?#32440;?#30721;被用于提供示例,但是由
示例描述的?#38469;?#19981;限制于Java、JVM或任何特定语言或虚拟机架构。

在一些实施例中,通过首先执行创建未初始化的对象的指令并且然后调用构造函
数来初始化对象。用于值类型的构造函数的行为与工厂方法更类似。下面示出?#23435;狿oint的
构造函数生成的示例性指令。



为了在栈帧400的局部变量401中创建Point的实例,工厂方法被调用,并且结果被
存储在?#38236;兀?br />


在上面的示例中,为了简化阐述,值类型的构造函数的名称被更改为<new>,以强
调该构造函数是工厂方法。

示例:?#30701;?#20540;



在上面的示例中,当读取?#30701;?#20540;时,首先读取它的封闭值。

示例:数组

在实施例中,利用vnewarray指令来创建数组,并且非常像任何其他数组类型那样
操纵数组。以下是示例:


示例:方法调用

在实施例中,静态地解析对于值类型的方法。invokestatic指令对于调用值类型
的静态方法和非静态方法这二者(作为指令/?#32440;?#30721;语法)将会是足够的,但是为了清楚地
阐述,一些实施例对于值类型的非静态方法使用新的调用指令vinvoke。以下是示例:



示例:装箱

在一些实施例中,当值类型被指派了类型Object、它的箱类型或它实?#20540;?#25509;口类
型的变量时,变量的内容由编译器102和/或虚拟机104自动装箱。例如:



示例:拆箱

在实施例中,当值类型从类型Object、它的箱类型或它实?#20540;?#25509;口类型的变量被
分配时,首先检查引用以查?#27492;?#26159;否是对应的箱类型,并且(如果是的话)然后值被拆箱。以
下是示例:


在一些实施例中,装箱引用具有?#36816;?#30452;接调用的值类型的方法,例如:


示例:扁平化的散列表

在一些实施例中,因为值类型没有指针,所以值类型可以被用于通过移除间接寻
址的级别来使一些数据结构扁平化。扁平化不仅移除了来自关键路径的?#35272;?#24615;负载,而且
(典型地)将相关数据移动到相同的高速缓存线上。

在一些情况中,调优良好的、尺寸可变的散列表可以在不超过两个高速缓存线引
用中答复查询,其中一个引用用来针对表尺寸咨询表头部,一个引用用来探查表中的条目。
如果表条目在承载表的数据数组内是扁平化的,则这可以实现,并且在值类型的帮助下这
成为可能。


上面的代码实际上触摸了三个高速缓存线,以便于从数组头部提取数组长度。在
一些实施例中,解决该问题包括将数组长度向上提升到散列表头部中。

上面的代码避开将具有默认值的条目(零散列、空?#22336;?#20018;引用)与寻找条目失败区
分开的问题。这是使面向指针的算法(例如,在Java中)适应于值类型的典型问题。这可以由
不同的实施例以若干方式解决。一种方式是引入表达可选择的条目(条目加上?#32423;?#22411;)的
值,并且从getEntry返回该值。要注意在用于getEntry的慢路径的末端处,实现默认(空)条
目值的能力在此可以是有用的。出于上面给出的原因,默认值是一些语言景观(诸如Java)
的部分。

在上面的示例中,__AlwaysAtomic关键?#20540;?#25928;果是确保数组元素值在没有内部竞
争的情况下被一致地读取。在没有该修改的情况下,在一些平台上,结构撕裂可能导致值可
能与错误的键相关联的状态。该危害来自扁平化;它在数据结构的“指针丰富的”版本中不
会呈现。

在一些实施例中,计算平台能够借助于64位存储器引用来在没有额外成本的情况
下实现用于该数据结构的原?#26377;浴?#36825;假设值成分可以被打包为32位,这是通常的情况。在一
些情况中,甚至四个成?#20540;?#20540;可以容纳在128位中,并且大多数硬件平台以合理的成本提供
原子的128位读和写。对于较大的值,?#28909;?#20855;有五个或更多个成?#20540;?#20540;,用于原?#26377;?#30340;成本
将?#26412;?#22686;加,这是原?#26377;?#19981;是默认的原因。

要注意为了对于整型和?#22336;?#20018;型起作用,该示例性数据结构是“硬连线的”。对应
的泛型类将从扁平化的数组获得一些益处,但是可以不直接对拆箱的整型起作用。在一些
实施例中,虚拟机104实现类似模板的机制来对非引用进行参数化以解决该问题。

示例:比较

如上文所指出的,在一些实施例中值类型可以实现接口。这是支持比较的值类型
的示例:



自动创建的箱类适当地实现接口,桥接到所给出的compareTo方法。vinvoke指令
还可以直接调用如所编写的compareTo方法。

这是对接口函数的调用的一些示例。



像类那样,通常存在对实现接口的方法做出直接的、无接口的调用(在该情况中
vinvoke)的选项。

在上面的示例中,接口(诸如根据Java的当前规则)采用擦除的Object参量。在值
类型的背景下,允许类型参量(Comparable<T>中的T)绑定到值类型Bignum并且因此将箱方
法一直桥接到方法compareTo。

在一些实施例中,每个值类型实现自组织(ad hoc)接口或抽象超类型,诸如下面
的示例:


3.11附加的示例性选项

子类型化。在一些实施例中,虚拟机104创建用于值类型的新的根类型以支持用于
解析的抽象值超类型。

擦除vs.具体化。在实施例中,箱仅对箱操作,而值类型仅对值类型操作。某些桥方
法由虚拟机104(静态地或者动态地)自动生成。

按成分方法。在一些实施例中,按成分方法是默认的。例如,过度健谈的toString
方法可能彻底违背秘密值成?#20540;?#23553;装性。用于生成用于打印、比较、散列码等的按成分方法
的机制和策略可以为了选择性加入(opt-in)vs.选择性退出(opt-out)的正确混合而被平
衡。

增强的变量操作。在一些实施例中,比较和交换(CAS)和类似的操作作为直接暴露
CAS操作的单独特征的部分而被解决。在一些实施例中,在许多情况下值类型与引用和原生
一起合并到CAS和类似的操作中。

值/原生收敛(convergence)。在实施例中,原生被集成到值类型中(例如,__
ByValue class int{...}),并且成为预定义的值类型。

按字段的副作用。在一些实施例中,为了简化,值字段是被定为最终的。然而,在其
他实施例中,值字段可以不一定总是最终的。在一些实施例中,可以对值中的仅一个字段产
生副作用,从而实现“通过值”的所?#34892;?#29575;以及“通过引用”的所有可变性。

值上泛型。在一些实施例中,虚拟机104支持用于值类型的泛型(例如,List<Point
>)。

数组值。聚合的空间形成2×2的矩阵{标识,无标识}×{同构,异构}。对象和数组
填充“标识”行;值类型填充(无标识,异构)箱;剩余的箱可以被描述为数组值。在一些实施
例中,虚拟机104提供对于数组值的支持。

3.12从类型到值类型的迁移

在诸如Java之类的一些操作环境中,如果设施在许多之前实?#20540;?#31867;型写入?#24065;?#32463;
是可用的(例如,Java中的LocalDateTime、Integer等),假设在已经是值类型的时间处这些
类型已经是可用的,则许多之前实?#20540;?#31867;型可能应?#24065;?#32463;是值类型。在一些实施例中,虚拟
机104支持将以上提到的类型实现为值类型的能力同时维持API互操作性。

迁移兼容性具有两个重要的方面:二进制兼容性(当现有的二进制指代预先迁移
的类型时,二进制兼容性发生)以及源兼容性(当针对迁移的类型重新编译文件时,源兼容
性发生)。源兼容性一般要求?#24065;?#29992;类型被迁移为值类型时,对该引用类型的每个操作具有
兼容的含义;这不仅包括像构造和方法调用那样的值安全的惯用语法,而且包括诸如锁定
之类的值不安全的操作,因为现有代码可能执行?#35272;当?#35782;的操作。

假如预先存在的类型“WasARef”被迁移为值类型,并且由迁移注释为:

__Migrated__ByValue class WasARef{...}

以下事实帮助兼容性,即如果类“X”从引用类型迁移为值类型,则类型描述符“L
X;”在迁移后仍然是合法的类型,它指代现在的值类型的装箱形式。如上文所?#33268;?#30340;,用于
值类型的装箱版本的类文件可以从值类型的类文件生成。或者这二者可以共享公共的类文
件。因此,只要维?#33267;?#21629;名约定,那么导致类型不安全的操作或使用的对值类型的先前使用
可以替代地利用值类型的装箱版本。因此,为了提供用于迁移的类型的源兼容性,在一些实
施例中虚拟机104通过提供从“L”桥接到“Q”形式的桥方法来至少为迁移的所有值类解决值
不安全的操作,以使得重新编译的API继续与旧客户机工作。

3.13更新字段的值

在实施例中,虚拟机104被配置为针对?#22791;?#26032;一个字段和一些其他字段是易变的
时可能出?#20540;?#38382;题而使用指令的替代设计:


例如,如果代码显示为:

kludge k;

k.baz=7;

那么按照语句与以下语句同义的理论

k=kludge(k.flag,7);

可以写入“flag”字段。在实施例中,虚拟机104提供对于具有可以独立写入的两个
易变字段的“像值一样的”结构的支持。然而,为了弥补,源语言可以在语言级别实?#25351;?#31934;心
制定的语义。例如,源语言可以遵循诸如“当且仅当值类型是变量的值时,值类型的字段是
变量”之类的规则。因此,如果以下语句是合法的,

c.im=7;

则以下语句是不合法的:

myComplexHashMap.get(key).im=7;

只要在更新变量的字段时保持变量中的复数值,那么编码员可以在使用用于复数
的值类和非值类之间高效地来回移动。

同时,能够独立写入值的两个(可能易变的)字段中的每个字段的虚拟机104指令
可以被提供。因此,在一些实施例中,以下?#38469;酰?#19981;向上面介绍的那些添?#26377;?#30340;虚拟机104指
令,却将作为vstore或vastore指令的部?#20540;摹癲esc”从

Q-descriptor

概括为

Q-descriptor(.field-name)*

结果,描述符可以不仅描述值类型,而且可以描述该值类型的任何字段或子字段。

按照该方法,编译

c.im=7;

的示例性方式是

bipush 7

vstore"Qcomplex;.im"3

而编译

c.im*=trouble();

的示例性方式是

vload 3//c

vgetfield"Qcomplex;.im"

invokewhatever"trouble"

mul

vstore"Qcomplex;.im"3

因此,如果vload和vaload被扩展(以及可能vreturn和vgetfield和vputfield被
扩展)以采用这些扩展的描述符(也可能为了对称),则它变成:

vload"Qcomplex;.im"3

invokewhatever"trouble"

mul

vstore"Qcomplex;.im"3

如果p是具有被命名为“phase”的类型复数的字段的值类型“foo”的变量,则编译

p.phase.im*=trouble();

的示例性方式是

vload"Qfoo;.phase.im"4

invokewhatever"trouble"

mul

vstore"Qfoo;.phase.im"4

该方法在某些方面比vputfield/dup_X1跳跃更高效。用于将看上去像是链式字段
访问的东西打包成单个描述符的正当理由是它毕竟只是个描述符;它解析为单个偏移并且
在一些实施例中使用它的vload或vstore仅执行?#28304;?#20648;器的一次读或写操作。

在一些实施例中,类型检查弥补了上面所描述的?#38469;酢?#20363;如,对于vload"Qfoo;
.phase.im"4,局部变量槽4中的数量的类型必须是Qfoo;,但是加载到栈上的元素具有与子
字段的类型.phase.im相等的类型,它可以是双精度型或整型,这取决于复数的实现。

4.0修改后的加载进程

在一些实施例中,虚拟机104修改上文在“加载、链接和初始化”中所描述的加载进
程来弥补值类型的引入。本节描述所述?#38469;?#21487;以被修改的若干示例性方式。然而,示例仅适
用于特定实施例并且不是决定性的。

如上文所描述的,当类文件200被加载到虚拟机存储器布局300中时,存储器被分
配给所加载的类的静态字段。在类的静态字段具有值类型的情况下,然后在一些实施例中,
需要被分配的空间量位于用于值类型的类文件中而不是在用于当前类的类文件中。结果,
虚拟机104基于为被加载的类的类文件中的字段指定的符号引用来定位值类的类文件,并
且计算所需要的存储器的量。不过,如果用于值类的类文件已经被加载,则虚拟机104可以
执行计算并且在与指示总尺寸的值类相关联的元数据中高速缓存结果。该元数据然后可以
被虚拟机104读取,而不是多次执行计算。例如,需要由虚拟机104为该字段在共享区域301
中分配的空间量将是值类型的成?#20540;?#21644;。这具有如下警告,即如果值类型具有值类型的字
段(假设实施例允许这样的字段),则所需要的存储器的计算被递归地执行,对总数进行合
计。

类似地,如果所加载的类的实例在堆302上被创建,则用于保持值类型的实例字段
的所需要的空间量可以以相同的方式计算。可替代地,该计算可以提前执行并且高速缓存
为与值类型和/或对象类相关联的元数据,以防止虚拟机104必须在每次实例化对象类时执
行计算。

5.0存储考虑

如上文所?#33268;?#30340;,值类型打算使用扁平化表示来存储并且通过值传递。因此,当在
保持值类型的堆302上创建对象时,值类型的内容被存储在对象内,而不是被分配在堆302
上的单独区域中的对值类型的引用。此外,当值类型被加载到栈帧400中时,是值类型的内
容被复制到局部变量401和/或操作数栈402中,而不是引用。

在一些实施例中,局部变量401表示保持一个或多个“容器”的数据结构,诸如保持
若干槽以存储用于局部变量401的各个值的数组。分配用于局部变量401的空间的一种?#38469;?br />是分配具有固定尺寸的容器。例如,虚拟机104可以分配数组,在该数组中每个槽被设定尺
寸以适配原生或引用。因此,原生通过值被存储在槽中,而非原生被分配在堆302上并且在
槽中存储对堆302的引用。在一些情况中,表?#24452;?#20010;其他原生的原生(诸如双精度型)被看作
占用多个槽。然而,值类型由用户定义并且因此可以具有可能不整齐地适配固定尺寸的容
器的可变尺寸。

在一些实施例中,诸如当JIT编译器109接管并?#20918;?#35793;正被执行的一个或多个方法
的虚拟机104指令时,执行代码的全局分析。结果,虚拟机104可以确定执行特定的经编译的
方法将需要的容器尺寸。然而,当使用解释器108时,虚拟机104在没有全局分析的益处的情
况下一次一个指令地执行程序。因此,当栈帧400(例如,作为方法调用的结果)被创建时所
分配的用于局部变量401的容器可能被设定了不足以处理特定值类型的尺寸。例如,假设局
部变量401包括两个容器,各自分配了64位的存储器。如果给定方法的虚拟机104指令指定
将诸如整型之类的较小的值存储到第一容器中,则存储器分配可能是低效的(分配多于需
要的空间),但是整型可以被存储在容器中。然而,如果虚拟机104指令指定在容器中存储
128位值类型,则容器对于容纳值类型而言将不够大。作为响应,虚拟机104会将容器重新分
配为128位以便于存储值类型。因此,存在与过大地设定被用于存储局部变量401的容器的
尺寸相关联的存储开销以及与过小地设定容器的尺寸并且执行频繁的重新分配相关联的
处理开销。

在一些实施例中,操作数栈402还被实现为存储一个或多个容器的数据结构。例
如,操作数栈402可以被实现为存储以先进先出(FIFO)顺序访问的一个或多个容器的栈或
分段的栈。因此,在一些实施例中,将值类型存储到操作数栈中可以导致上面关于局部变量
401所?#33268;?#30340;相同问题。

在一些实施例中,虚拟机104实现分配规则和存储优化,该分配规则和存储优化降
低了与在容器中存储尺寸可变的值(诸如值类型)相关联的开销。

5.1存储过程流

图5示出了根据实施例的用于在容器中存储值类型的过程。如上文所?#33268;?#30340;,局部
变量401和操作数栈402这二者都可以被实现为存储容器的数据结构。然而,图5中示出的过
程流对于被用于存储容器的数据结构是通用的。此外,图5中框执行的顺序不是关键的。在
其他实施例中,与图5的图示相比,框可以被重新排列、合并或者划分为分开的框。下面的解
?#22270;?#35774;图5的过程流由虚拟机104的解释器108执行。另外,下面的解?#22270;?#35774;在图5的过程期
间帧400是当前栈帧。

在框500处,解释器108初始化一个或多个容器。在一些实施例中,当响应于方法调
用而创建新的栈帧400时执行框500。例如,该一个或多个容器可以表示用于存储局部变量
401的数据结构和/或用于存储操作数栈402的数据结构。

在实施例中,解释器108将所述一个或多个容器初始化为具有相同的固定尺寸。例
如,解释器108可以将容器初始化为存储基本原生和/或引用所需要的尺寸。作为另一示例,
解释器108可以创建具有大于基本原生和/或引用的尺寸的固定尺寸的容器。

在一些实施例中,解释器108将所述一个或多个容器初始化为可变的尺寸。例如,
在一些实施例中,当方法被调用时,新的栈帧400被创建,前一个帧的操作数栈上的参数出
栈并?#20918;?#25918;置在新栈帧400的局部变量401中。因此,至少对于被用于存储参数的容器而言,
解释器109可以将这些容器初始化为适合于方法调用所期待的参数类型(诸如原生类型、引
用类型或值类型)的尺寸。例如,解释器108可以通过检查方法调用的描述符来确定参数类
型。

然而,在一些实施例中,栈帧在存储器中重叠以提升存储效率。例如,调用者的栈
帧可以与被调用者的栈帧在存储器中重叠,使得调用者的操作数栈是与新栈帧的一个或多
个局部变量相同的存储器位置。在这样的实施例中,当调用者将这些值推到前一帧的操作
数栈上时,表示参数的局部变量401的容器被初始化。

在一些实施例中,解释器108可能仍然需要用于在方法的主体内声明的变量(例
如,无参数的局部变量)的容器。在一些实施例中,解释器108预先分配若干容器以保持这种
变量的值。然而,在其他实施例中,解释器108?#26144;?#21021;始分配直至接收到将值存储到局部变
量中的指令。一旦接收到指令,则解释器108分配对于存储该值来说足够大的容器。例如,容
器可以通过编号(1、2、3、4等)索引,如果接收到在尚未被分配的容器的索引号处存储值的
指令,则解释器108分配对于保?#25351;?#20540;来说足够大的容器。在一些实施例中,解释器108修改
用于保持容器的数据结构的元数据和/或头部信息以将索引号?#25104;?#21040;容器。

在框501处,解释器108接收在所分配的容器中存储值类型的指令。在实施例中,作
为逐句通过被调用的方法的代码的结果,解释器108接收指令。在框501处可以被解释器108
接收的指令示例包括vstore、vastore、vload、vaload和上文描述的用于值类型的其他指
令。在一些实施例中,在框501处接收的指令表示“较高级别的”指令(诸如JVM?#32440;?#30721;),解释
器108的任务是将该“较高级别的”指令翻译成一个或多个“较低级别的”指令,诸如被调整
为适应执行虚拟机104的计算机?#20302;?#30340;处理器的机器码。

在框502处,解释器108向验证器106馈送指令以针对一批规则进行检查。在一些实
施例中,规则被设计为创建关于解释器108的复制和/或重新分配努力的界限。在一些实施
例中,当验证器106检测到规则被违背时,验证器抛出异常,该异常由特殊的异常代码来处
理。

在实施例中,验证器106?#38469;?#23481;器以在被分配为用于一个种类的值类型后仅保持
该值类型。因此,如果容器被分配为保持特定尺寸的值类型,则验证器106阻止容器被用于
可能具有不同尺寸要求的任何其他种类的值类型。结果,验证器106阻止解释器108付出努
力重新分配用于多个值类型的容器。然而,在一些实施例中,解释器108允许容器被重新指
派为其他值类型,假设该值类型有相同的尺寸(或者在一些实施例中,有较小的尺寸)。在一
些实施例中,前面提到的?#38469;?#34987;维?#31181;?#33267;容器的类型被“重置”或者指派的值被移动到其他
地方。例如,“重置”指令可以重置类型和内容,而“移动”指令将重置类型以及将内容重新指
派到另一容器(诸如在操作数栈402的顶部上)。然而,对于不实现这种指令的实施例,一旦
被设置,则对于方法调用的剩余部分,类型可以被永久指派到容器。

在框503处,解释器108确定值类型是否适配所分配的容器。在实施例中,如果值类
型具有与所分配的容器相同或者比分配的容器更小的尺寸,则解释器108前进到框504。否
则,如果值类型比分配的容器的尺寸更大,则解释器前进到框505。

在框504处,解释器108将值类型的内容存储到容器中。

在框505处,解释器108确定值类型要通过引用还是通过值来存储。在一些实施例
中,解释器108考虑各种因素来确定值类型要通过引用还是通过值来存储在容器中。例如,
因素可以包括容器的性质、值类型的成分、较低级别的指令如何利用值类型、另一容器是否
已经存储值类型等?#21462;?#22312;一些实施例中,如果值类型大于阈值尺寸并?#20918;?#30830;定为不可变,则
解释器108选择通过引用来存储值类型。因此,对于大的值类型,解释器108可以选择存储对
值类型的引用而不是复制值类型的内容。结果,通过阻止重复复制尺寸过大的值类型可以
实?#25191;?#20648;和处理高效率。然而,由于值类型被保证是不可变的,因此从用户的视角来看,不
存在副作用的风险;原生值与值类型的处置之间不存在区别。如果解释器108确定要通过值
存储值类型,则解释器108前进到框506。否则,如果解释器108确定要通过引用存储值类型,
则解释器108前进到框507。

在框506处,解释器108调整容器的尺寸。在一些实施例中,解释器108通过对容器
解除分配并且然后将容器重新分配为足以存储值类型的尺寸来调整容器的尺寸。然而,在
其他实施例中,取决于被用于存储容器的数据结构,解释器108可以被配置为在不执行解除
分配的情况下分配更多的存储器以增加容器的尺寸。

在框507处,解释器108在堆302上为值类型分配空间。在实施例中,解释器108查找
值类型的尺寸并且在堆302上分配对于存储值类型来说足够大的空间。然后解释器108在分
配的空间处在堆302上存储值类型。

在框508处,解释器108在容器中存储对值类型的引用。在实施例中,在框507处解
释器108存储对在堆302上为值类型分配的空间的引用。

在一些实施例中,在框505处的确定中,因素是另一容器是否已经存储用于值类型
的值的拷贝。在这种情况中,如果解释器108确定将值类型存储为引用,而不是在堆302上存
储值类型并且在容器中存储对堆302的引用,则解释器108在容器中存储?#28304;?#20648;值类型的其
他容器的引用。例如,并非将来自局部变量的值类型复制到操作数栈402,解释器108可以替
代地复制?#28304;?#20648;用于该局部变量的值类型的容器的引用。作为另一示例,并非将来自局部
变量的值复制到另一局部变量,解释器108可以替代地复制?#28304;?#20648;第二个局部变量的值的
容器的引用。在一些实施例中,仅当容器中的值不可变时才执行前面提到的优化,以防止副
作用。

6.0原子操作

在一些实施例中,虚拟机104被配置为允许值类型或值类型的选定字段被原子地
访问。因此,向虚拟机104中的每个运行的线程提供值类型(或选定字段)的一?#29575;?#22270;。例如,
值类型可以是具有由用户定义的多个成?#20540;?#22797;合。取决于虚拟机104运行在其上的硬件,处
理器的指令集可能不具有支持一次更新整个值类型的指令。作为示例,当构造函数为一个
线程构造值类型时,另一个线程可能看到该值类型的不一致的视图,其中仅仅值类型的一
部分已经更新。许多类型的硬件提供了用于执行原子操作的机制,但是这些机制具有不同
程度的开销。此外,在一些情况中,硬件机制可能是不够的;这使得经常发生的由软件实现
的锁定方案具有非常高的开销。因此,在一些实施例中,语言允许值类型被加标志以用于在
诸如整个值类型、值类型中的选定字段或者访问值类型的独个指令之类的不同粒度级别的
原子访问。

在一些实施例中,仅当值类型被存储在堆302上时遇到竞争状况和原?#26377;?#30340;问题。
这是因为在一些实施例中堆302存储在线程之间共享的数据,但是线程区域307(包括虚拟
机栈)存储仅能被独个线程访问的数据。因此,(通过值)存储在栈帧400中的值类型不经历
竞争状况,因为仅一个线程将访?#25910;?#20123;值类型。然而,当值类型例如作为封装对象的字段被
存储在堆302上时,多个线程可以潜在地读取该值,从而导致竞争状况。

图6示出了根据实施例的用于访问值类型的过程流。为了示出清楚的示例,将?#26377;?br />拟机104的解释器108的视角来说明图6的过程流。

在框600处,解释器108接收访问存储在容器中的值类型的字段的指令。在一些实
施例中,解释器108接收从值类型的字段加载值或将值存储到值类型的字段的指令。例如,
上文描述的vgetfield和vputfield指令是在框600处可以接收的指令的示例。

在框601处,解释器108确定字段是否要被原子地?#28304;?#22914;果是,则解释器108前进
到框602。否则,解释器108前进到框602。在实施例中,响应于检测到以下情况中之一,解释
器108确定字段是原子的:值类型已经被标记为始终是原子的,值类型的字?#25105;?#32463;被单独地
标记为用于原子访?#21097;?#25110;者指令被标记为是原子指令。例如,在源代码文件101中,值类型的
声明、值类型的字段或使用值类型的指令包括诸如“atomic(原子的)”或“always atomic
(始终是原子的)”之类的关键字。当编译器102编译源代码文件101时,利用指示这些成分要
被原子地?#28304;?#30340;标志或元数据来标记类文件103。然后解释器108可以读取这些类文件103
(或者加载到虚拟机存储器布局300中的类文件103的表示)以确定字段是否要被原子地对
待。

在框602处,解释器108在没有原子限制的情况下执行访问。例如,解释器108可以
通过将访?#39318;?#25442;为不提供任何原子保证的较低级别的指令而在没有原子限制的情况下执
行访问。

在框603处,解释器108确定字段是否是不可变的。在一些实施例中,字段或值类型
作为整体与源代码文件101中指示字段或值类型被冻结并且不能改变的关键字相关联。类
似于上文描述的“atomic”关键字,这可以作为标志或元数据被反映在类文件103和/或虚拟
机存储器布局300中以供解释器108在框603期间读取。如果字段是不可变的,则解释器108
前进到框602。如果字段是可变的,则解释器108前进到框604。

在框604处,解释器108确定字段是否被频繁访问。在一些实施例中,解释器108跟
踪在每次访问期间递增的与值类型的字段或值类型本身相关联的元数据。如果元数据指示
访问的数量超过了特定阈值,则解释器108确定该字段被频繁访问。然而,在其他实施例中,
还考虑时间分量,诸如追踪在时间的某个表示(真实时间、计算机时间、所执行的指令的数
量等等)内访问的数量。如果解释器108确定字段被频繁访?#21097;?#21017;解释器108前进到框605。如
果解释器108确定字段不被频繁访?#21097;?#21017;解释器108前进到框606。

在框605处,解释器108在分开的容器中存储字段。在一些实施例中,解释器108将
字?#26410;?#25153;平化的形式改变为引用表示。与扁平化的值相比,对于原子地访问来说引用通常
更快。例如,对于放置/存储指令,字段的新值可以在堆302上创建并且可以通过更新对新存
储器位置的引用来原子地更新字段。此外,对于原子的加载,只要字段经由指针更新,则被
加载的值要么表示整个新值要么表示整个旧值,而不可能保留部?#25351;?#26032;的值。因此,可以避
免诸如锁定之类的需要显著开销的原子?#38469;酢?br />

在框606处,解释器108原子地执行访问。在实施例中,解释器108在框606处从多个
?#38469;?#20013;选择对于当前环境而言最高效的特定?#38469;酢?#20363;如,执行虚拟机104的硬件可以支持可
被用于原子地执行访问的事务或者其他基于硬件的原子指令。然而,在一些情况中,硬件可
能不支持足以执行访问的原子指令,因此在这种情况下解释器108回退到基于软件的原子
?#38469;酰?#35832;如执行锁定。在实施例中,只要可能,相比于基于软件的?#38469;酰?#35299;释器108优选基于
硬件的原子指令。然而,在其他实施例中,解释器108能够访问指示?#38469;?#30340;排名的元数据。例
如,当程序运行时,解释器108可以尝试各种类型的原子访问?#38469;?#24182;?#19968;?#20110;速度将这些?#38469;?br />排名。

7.0硬件概述

根据一个实施例,本文描述的?#38469;?#30001;一个或多个专用计算设备实现。专用计算设
备可以被硬连线以执行所述?#38469;酰?#25110;者可以包括被永久编程为执行所述?#38469;?#30340;诸如一个或
多个专用集成电路(ASIC)或现场可编程门阵列(FPGA)之类的数?#20540;?#23376;设备,或者可以包括
被编程为根据固件、存储器、其他存储设备或者组合中的程序指令来执行所述?#38469;?#30340;一个
或多个通用硬件处理器。这种专用计算设备还可以将定制的硬连线逻辑、ASIC或FPGA与定
制的编程相组合以实现所述?#38469;酢?#19987;用计算设备可以是含有用于实现所述?#38469;?#30340;硬连线逻
辑和/或程序逻辑的桌上型计算机?#20302;场?#20415;携式计算机?#20302;场?#25163;持设备、联网络设备或任何
其他设备。

例如,图7是示出在其上可以实现本发明的实施例的计算机?#20302;?00的框图。计算
机?#20302;?00包括用于传送信息的总线702或其他通信机构,以及用于处理信息的、与总线702
耦接的硬件处理器704。硬件处理器704可以是例如通用微处理器。

计算机?#20302;?00还包括用于存储信息和要由处理器704执行的指令的、耦接到总线
702的主存储器706(诸如随机存取存储器(RAM))或其他动态存储设备。主存储器706还可以
被用于在要由处理器704执行的指令的执行期间存储临时变量或其他中间信息。这种指令
当被存储在处理器704可访问的非暂态存储介质中时,使计算机?#20302;?00成为被定制为执行
指令中指定的操作的专用机器。

计算机?#20302;?00还包括存储用于处理器704的静态信息和指令的、耦接到总线702
的只读存储器(ROM)708或其他静态存储设备。诸如?#25490;獺?#20809;盘或固态驱动器之类的存储设
备710被提供并?#20918;获?#25509;到总线702以用于存储信息和指令。

计算机?#20302;?00可以经由总线702耦接到诸如发光二极管(LED)显示器之类的显示
器712以用于向计算机用户显示信息。包括字母数字键和其他键的输入设备714被耦接到总
线702以用于向处理器704传送信息和命令选择。另一种类型的用户输入设备是用于向处理
器704传送方向信息和命令选择以及用于控制显示器712上的光标移动的光标控制器716,
诸如鼠标、跟踪球或光标方向键。该输入设备典型地具有允许设备在平面上指定位置的在
第一轴(例如,x)和第二轴(例如,y)这两个轴上的两个自由度。

计算机?#20302;?00可以通过使用与计算机?#20302;?#32467;合使得计算机?#20302;?00成为专用机
器或者将计算机?#20302;?00编程为专用机器的定制的硬连线逻辑、一个或多个ASIC或FPGA、固
件和/或程序逻辑来实现本文描述的?#38469;酢?#26681;据一个实施例,本文的?#38469;?#30001;计算机?#20302;?00
响应于处理器704执行包含在主存储器706中的一个或多个指令的一个或多个序列来执行。
这种指令可以从诸如存储设备710之类的另一个存储介质读取到主存储器706中。包含在主
存储器706中的指令序列的执行使得处理器704执行本文所描述的过程步骤。在可替代的实
施例中,硬连线电路可以代替软件指令使用或与软件指令结合使用。

如在此所使用的术语“存储介质”是指存储使得机器以特定方式操作的数据和/或
指令的任何非暂态介质。这种存储介质可以包括?#19988;资?#24615;介质和/或?#36164;?#24615;介质。?#19988;资?#24615;
介质例如包括光盘、?#25490;?#25110;固态驱动器,诸如存储设备710。?#36164;?#24615;介质包括动态存储器,诸
如主存储器706。常见形式的存储介质例如包括软盘、柔性盘、硬盘、固态驱动器、磁带或任
何其他磁数据存储介质、CD-ROM、任何其他光学数据存储介质、具有孔?#21450;?#30340;任何物理介
质、RAM、PROM和EPROM、FLASH-EPROM、NVRAM、任何其他存储器芯片或?#23567;?br />

存储介质不同于传输介?#21097;?#20294;是可以与传输介质结合使用。传输介质参与在存储
介质之间传送信息。例如,传输介质包括同轴线?#38534;?#38108;线和光纤,包括包含总线402的线。传
输介质还可以采取声波或光波的形式,诸如在无线电波和红外数据通信期间生成的声波或
光波。

各种形式的介质可以涉及将一个或多个指令的一个或多个序列承载到处理器704
以供执行。例如,指令可以初始地被承载在远程计算机的?#25490;?#25110;固态驱动器上。远程计算机
可以将指令加载到它的动态存储器中并且使用调制解调器通过电话线发送指令。计算机系
统700的?#38236;?#35843;制解调器可以接收电话线上的数据并且使用红外传输器将数据转换成红外
信号。红外检测器可以接收红外信号中承载的数据,并且合适的电路可以将数据放置在总
线702上。总线702将数据承载到主存储器706,处理器704从主存储器706检索指令并且执行
指令。由主存储器706接收的指令可以选择性地在被处理器704执行之前或之后存储在存储
设备710上。

计算机?#20302;?00还包括耦接到总线702的通信接口718。通信接口718提供耦接到网
络链路720的双向数据通信,网络链路720被连接到?#38236;?#32593;络722。例如,通信接口718可以是
综合业务数字网(ISDN)卡、线缆调制解调器、卫星调制解调器或者用于提供到对应类型的
电话线的数据通信连接的调制解调器。作为另一示例,通信接口718可以是局域网(LAN)卡
以提供到兼容的LAN的数据通信连接。无线链路也可以被实现。在任何这种实施方式中,通
信接口718发送和接收承载有表示各种类型的信息的数字数据流的电信号、电磁信号或光
信号。

网络链路720典型地通过一个或多个网络提供到其他数据设备的数据通信。例如,
网络链路720可以通过?#38236;?#32593;络722提供到主机计算机724或?#25509;?#32593;络服务提供商(ISP)726
运营的数据装置的连接。ISP 726又通过现在通常被称为“互联网”728的全球分组数据通信
网提供数据通信服务。?#38236;?#32593;络722和因特网728都使用承载有数字数据流的电信号、电磁
信号或光信号。通过各种网络的信号和在网络链路720上并通过通信接口718的信号是传输
介质的示例形式,这些信号承载有到计算机?#20302;?00的数字数据以及来自计算机?#20302;?00的
数字数据。

计算机?#20302;?00可以通过网络、网络链路720和通信接口718来发送消息和接收包
括程序代码的数据。在互联网示例中,服务器730可以通过互联网728、ISP 726、?#38236;?#32593;络
722和通信接口718来传送用于应用程序的请求的代码。

所接收的代码可以如它被接收的那样由处理器704执行,和/或被存储在存储设备
710或者其他?#19988;资源?#20648;中以便以后执行。

如本文所使用的,术语“一个”、“两个”、“某个”和“特定”被用作命名约定以将查
询、计划、表示、步骤、对象、设备或其他项彼此区分开,以使得这些项可以在它们被介绍之
后被引用。除非在此另外指定,这些术语的使用不暗示所引用的项的顺序、时序或任何其他
特性。

8.0扩展和替代

在上面的说明书中,已经参照随着实施方式不同而不同的许多具体?#38468;?#25551;述了本
发明的实施例。因此,本发明是什么以及申请人意图本发明是什么的唯一且排他的指示物
是以权利要求发布的具体形式从本申请中发布的一组权利要求,包括任何后续补正。针对
权利要求中所包含的术语,本文明确阐述的任何定义应当决定如权利要求中使用的这些术
语的含义。因此,在权利要求中没有明确表述的限制、要素、性质、特征、优点或属性都不应
?#24065;?#20219;何方?#36739;?#21046;这些权利要求的?#27573;А?#22240;此,说明书?#36879;?#22270;应被视为是说明性的而非限
制性的。

9.0第一附加公开

本文所描述的主题的方面列举在以下标号的条款中:

1.一种方法,包括:接收指定将特定值类型的值指派到多个容器中的特定容器的
一个或多个较高级别的指令,其中所述多个容器表示用于在代码块的执行期间维护一个或
多个变量的数据结构,其中所述多个容器中的至少两个容器具有不同的尺寸;基于根据所
述特定值类型将一个或多个指派规则应用于所述一个或多个较高级别的指令,生成将所述
值指派到所述特定容器的一个或多个较低级别的指令;执行所述一个或多个较低级别的指
令;其中所述方法由一个或多个计算设备执行。

2.如条款1所述的方法,其中所述一个或多个指派规则包括以下中的一个或多个:
限制哪些值类型能够被指派到所述特定容器的?#38469;?#22312;向所述特定容器中加载所述值的拆
箱表示或?#21592;?#25345;所述值的第二容器的引用之间进行选择的规则。

3.如条款2所述的方法,其中在向特定容器中加载所述值的所述拆箱表示或?#21592;?br />持所述值的第二容器的引用之间进行选择的规则基于以下中的一项或多项:所述值是否是
不可变的、所述值是否能够适配在所述特定容器内、所述值是否超出了特定的尺寸阈值、所
述多个容器中的另一个容器是否已经存储了所述值、所述值的成?#20540;?#24615;质、或者所述一个
或多个较低级别的指令将如何利用所述值。

4.如条款2-3中的任一项所述的方法,其中所述多个容器被存储在为多个线程中
的特定线程预留的存储器位置中,并且所述第二容器在由所述多个线程共享的存储器位置
中位于所述多个容器的外部。

5.如条款2-4中的任一项所述的方法,其中所述?#38469;?#22522;于以下中的一项或多项:
(1)确定所述特定容器已经被分配为适配一个或多个值类型,并且将对所述特定容器的指
派限制为所述一个或多个值类型的值,(2)将对所述特定容器的指派限制为与所述特定容
器共享尺寸的值或具有比所述特定容器小的尺寸的值,(3)将对所述特定容器的指派限制
为一个或多个特定值类型直至接收到重置所述特定容器的指令。

6.如条款2-5中的任一项所述的方法,还包括:响应于确定要在所述特定容器中加
载所述值的所述拆箱表示以及确定所述特定容器不能适配所述值,调整所述特定容器的尺
寸以适配所述值。

7.如条款1-6中的任一项所述的方法,还包括:接收指定改变第二特定容器中存储
的第二值的成?#20540;?#19968;个或多个第二较高级别的指令,其中所述第二值具有第二特定值类
型;至少部?#20540;?#22522;于与所述第二特定值类型相关联的元数据来生成识别所述第二特定容器
的与所述成分部分对应的部?#20540;?#21333;个较低级别的指令;执行所述单个较低级别的指令。

8.如条款2-7中的任一项所述的方法,其中识别所述第二特定容器的所述部分包
括以下中的一项或多项:使用对应于所述第二特定值类型的值类型定义的字段定义来定位
所述部分,使用所述值类型定义的访问控制信息来实行对所述部?#20540;?#35775;问限制,或者基于
所述值类型定义来执行类型检查。

9.如条款1-8中的任一项所述的方法,还包括:接收指定访?#23454;?#20108;特定容器中存储
的第二值的成?#20540;?#19968;个或多个第二较高级别的指令,其中所述第二值具有第二特定值类
型;基于与所述第二特定值类型相关联的元数据来确定对所述成?#20540;?#35775;问是否应当是原子
的;响应于确定对所述成?#20540;?#35775;问应当是原子的,确定所述成分是否存储在不可变容器中;
响应于确定所述成?#25191;?#20648;在不可变容器中,生成不提供原子保证的一个或多个第二较低级
别的指令并且执行所述一个或多个第二较低级别的指令;响应于确定所述成分没有存储在
不可变容器中,选择能够提供对所述成?#20540;脑?#23376;访问的一个或多个机制中的特定机制,基
于所述特定机制生成提供原子保证的一个或多个第三较低级别的指令,以及执行所述一个
或多个第三较低级别的指令。

10.如条款2-9中的任一项所述的方法,其中所述第二值存储在第一容器中,并且
所述方法还包括:响应于确定所述成分没有存储在不可变容器中,确定所述成?#20540;?#35775;问频
率是否超过访问阈值;响应于确定所述成?#20540;?#25152;述访问频?#39135;?#36807;所述访问阈值,将所述成
?#25191;?#20648;在分开的第二容器中并且针对所述成分在所述第一容器中存储对所述第二容器的
引用。

11.如条款2-10中的任一项所述的方法,其中能够提供对所述成?#20540;脑?#23376;访问的
所述一个或多个机制基于由所述一个或多个计算设备的一个或多个处理器支?#20540;?#19968;组指
令。

12.存储有指令的一个或多个计算机可?#20004;櫓剩?#25152;述指令当被一个或多个计算设
备执行时使得执行如条款1-11中的任一项所述的步骤。

13.一种?#20302;常?#35813;?#20302;?#21253;括一个或多个计算设备,所述一个或多个计算设备包括至
少部?#20540;?#30001;计算硬件实?#20540;摹?#34987;配置为实现如条款1-11中的任一项所述的步骤。

10.0第二附加公开

根据实施例,诸如当将Java或其他源代码编译为?#32440;?#30721;或在任何其他合适的编程
环境中时,根据较高级别的指令生成较低级别的指令。较低级别的指令包括访问诸如运行
时数据区域的局部变量、栈元素、寄存器、虚拟寄存器和/或其他命名的虚拟变量的之类的
容器内的值的指令。容器具有变化的尺寸以便于例如能够直接地而不是通过对堆或其他存
储器区域中的容器的引用来存储具有可变尺寸的值。

较高级别的指令包括某个值类型的值。值可以是例如由若干成分组成的非原生的
复合值,诸如Point或Complex。该某个值类型可以例如由类定义,其中该类的值是实例。响
应于较高级别的指令,较低级别的指令可以被生成以将值或者(在一些情况中)对值的引用
加载到尺寸可变化的容器之一。这种较低级别的指令的一个示例是本文所描述的vaload指
令。或者,较低级别的指令可以存储、修改、移动和/或重置容器。在任何一种情况中,基于特
定值类型以及基于与特定值类型相关的一个或多个指派规则来生成较低级别的指令。这种
指派规则可以被配置为例如限制与维护支持可变尺寸的容器而非具有预定义的固定尺寸
的容器相关联的成本,和/或限制维护在容器之间复制的值的多个拷贝的成本。

在实施例中,指派规则可以包括例如一个或多个?#38469;?#22312;该一个或多个?#38469;?#19979;,在
方法的调用期间,不同的值类型可以被加载到容器中。在实施例中,这种?#38469;?#30340;一个示例可
以指定在方法的过程期间被加载到容器中的值可以具有最多一种数据类型或者数据类型
的有限集合。因此,给定的容器可以仅保持容器最初被分配的值类型的值以及选择地保持
原生或引用的值。选择性地,该?#38469;?#21487;以?#20013;?#33267;容器的类型被重置或者被指派的值被移动
到其他地方为止。例如,“重置”指令将重置类型以及内容,而“移动”指令将重置类型以及将
内容重新指派到另一个容器,诸如栈的顶部。移动操作将线性类型或所有权(ownership)类
型的概念应用于解释器效率。

在实施例中,另一示例性?#38469;?#21487;以是被指派到容器的值必须全部具有如下值类
型:该值类型被保证具有不大于指定尺寸的尺寸或者可替代地被保证具有与指定尺寸完全
相同的尺寸。在实施例中,另一示例性?#38469;?#21487;以是在方法的过程期间被记载到给定容器的
值可以具有变化的数据类型,但是如果给定容器被用于存储值类型,则它不能被用于存储
不同的类型(可选择地,直至容器被重置)。

在实施例中,指派规则的另一示例是在将值的拆箱表示或者?#21592;?#25345;值的外部容器
的引用加载到容器中之间最优地选择的规则。这种规则可以考虑诸如外部容器或值的成分
的性质或较低级别的指令内如何利用值之类的因素。例如,规则可以基于值在外部容器内
是否?#34892;?#22320;是不可变的。在实施例中,指派规则的另一示例是关于当第二容器已经包含第
一容器的值的拷贝时将值加载到第一容器中的?#38469;?#20219;何其他合适的指派规则也可以同时
或者替代地被利用。

根据实施例,在一组指令的验证(诸如在解释器解释?#32440;?#30721;之前由?#32440;?#30721;验证器
进行的验证)期间执行某些步骤。例如,当验证根据上文所描述的?#38469;?#29983;成的较低级别的指
令时,步骤可以被执行。所述步骤包括识别将值加载到具有变化的尺寸的一组容器中的容
器的指令。步骤还包括基于要被加载在容器中的值的值类型来验证指令遵从一个或多个约
束。在实施例中,?#38469;?#21487;以包括上文所描述的指派规则和/或?#38469;?#20013;的一个或多个。

根据实施例,当从较高级别的指令生成较低级别的指令时,改变某个值类型的值
内的字段的一个或多个较高级别的指令可被识别。值可以是例如潜在地具有多个不同成分
字段的值类型的实例。本文描述了这种值类型的示例,诸如Point或Complex。可以确定的
是,在较低级别的指令的背景下,用于值的至少一个成分字段的数据将被集体存储在单个
容器内。例如,字段可以被存储为其对应的子值的拆箱表示,而不是?#28304;?#20648;对应的子值的其
他容器的引用。响应于该确定,单个较低级别的指令被生成。这种较低级别的指令的示例是
本文所描述的vput指令。

所生成的单个较低级别的指令被配置为命令解释器识别容器的对应于字段的部
分,诸如一个或多个位。单个较低级别的指令还被配置为命令解释器根据一个或多个较高
级别的指令改变该部分。识别和/或改变可以至少部分基于与值的值类型相关联的元数据。
例如,指令可以使得解释器使用值类型的字段定义来定位该部分,和/或实行用于对应的值
类型定义的访问控制信息和类型检查?#21462;?#22312;实施例中,单个较低级别的指令命令解释器在
不使用指针来定位字段和/或不必发出打开值进入到其成分字段中的另一命令的情况下来
执行这些操作。

在实施例中,通过重新排序、合并或分开与彼此相关并且与可以读取或写入存储
在容器中的值或该值的至少一些成分字段的任何其他指令相关的两个或更多个这种较低
级别的指令的效果,选择地生成较低级别的指令。这种效果的重新排序、合并或分开可以经
受保护存储在容器中的值的每个成分字段以及作为整体存储在容器中的值的一致性的规
则。因此,?#38469;?#21487;以包括使用分层的数据结构的?#30701;状?#20648;器模型,当对象拆分成值时,该数
据结构可以拆分成更小的值并?#26131;?#32456;一直向下拆分成成分原生和引用。

根据实施例,方法包括:当解释诸如Java?#32440;?#30721;之类的指令时,识别用于插入较小
的第一值作为较大的第二值的字段的指令。该指令可以是例如单个较低级别的指令,诸如
上面生成的指令。第二值可以是例如具有被集体存储在容器中的多个不同成分字段的经定
义的值类型的值。第一值可以是例如对应于字段的子值。在实施例中,确定第二值具有某个
值类型。基于与某个值类型相关联的元数据,对应于字段的第二值的一部分被定位,并?#19994;?br />一值被加载到该部?#31181;小?#36825;可以包括例如基于与某个值类型相关联的值类型定义数据来实
行访问控制信息和类型检查,和/或使用值类型定义数据来定位相关部分。在实施例中,通
过重新排序、合并或分开两个或更多个这种较低级别的指令的效果来选择性生成较低级别
的指令,诸如上文所描述的。

根据实施例,代码可以访问意欲是原子的值的字段。这种代码可以包括例如诸如
getfield或putfield之类的指令。由于例如其值是实例的值类型的定义中的声明、或者当
值被实例化时的声明、和/或解释器或编译器的默认配置,值可以是原子的。响应于该代码,
编译器或解释器可以做出与决定在访?#39318;?#27573;时是否实现锁定策略和/或实现哪个锁定策略
相关的一个或多个确定。

在实施例中,一种这样的确定是字段是否为不可变的。例如,字段可以被局限于正
在执行的线程,字段可以是“冻结”的字段,和/或字段可以被声明为是最终的。如果字段不
可变,则可以生成在不锁定的情况下访?#39318;?#27573;的指令。在实施例中,另一种这样的确定是执
行硬件是否具有事务支持。如果是,则为了访?#39318;?#27573;生成对硬件的指令的事务版本,以便于
确保访?#26102;?#20197;事务方式处理。

在实施例中,另一种这样的确定是字段是否是频?#22791;?#21464;的和/或值是否是复杂的
或频繁访问的。如果是,则生成指令来将字?#26410;?#20648;在诸如通过指针在值内引用的容器之类
的分开的容器内,而不是直接将字?#26410;?#20648;在存储值的容器内。指令经由分开的容器访?#39318;?br />段。在实施例中,另一种这样的确定是值是否为已经被划分为子值的大值。值可以实?#23454;?#34987;
划分并且存储在分开的容器中,或者出于锁定的目的值可以在逻辑上被划分。如果值是已
经被划分为子值的大值,则通过锁定字段在其中驻留的子值来生成访?#39318;?#27573;的指令。在实
施例中,另一种这样的确定是值本身是否为另一个值的字段。如果是,则在此基础上选择锁
定策略。任何其他合适的确定可以被同时或者替代地做出。在实施例中,做出一系列的确
定。从资源的视角?#36824;?#35745;为最便宜的确定首先被执行,而其他确定仅在需要的时候执行。

在其他方面,公开了用于实现本文所描述的?#38469;?#30340;计算设备的?#20302;?#21644;计算机可读
介质。

关于本文
本文标题:处理值类型.pdf
链接地址:http://www.pqiex.tw/p-6091807.html
关于我们 - 网?#26087;?#26126; - 网?#38236;?#22270; - 资源地图 - 友情链接 - 网站客服 - 联系我们

[email protected] 2017-2018 zhuanlichaxun.net网站版权所有
经营许可证编号:粤ICP备17046363号-1 
 


收起
展开
平码五不中公式规律 老公赚钱老婆花语句 真人斗牛 北京时时赛车微信群 qt610793到底能不能赚钱 河南快赢481开奖直播 BETVICTOR伟德下载 欢乐二八杠安卓 威尼斯飞艇掌赢app 捕鱼达人安卓 21点游戏怎么玩