欧美在线观看视频网站,亚洲熟妇色自偷自拍另类,啪啪伊人网,中文字幕第13亚洲另类,中文成人久久久久影院免费观看 ,精品人妻人人做人人爽,亚洲a视频

處理值類型的制作方法

文檔序號:11160868閱讀:383來源:國知局
處理值類型的制造方法與工藝

實施例一般涉及用于在編程語言內(nèi)支持和/或利用值類型結構體的技術。



背景技術:

計算機語言提供許多不同的方法來創(chuàng)建聚合類型(aggregate type)。例如,諸如Java之類的語言提供具有標識(identity)的異構聚合(例如,“類”)和具有標識的同構聚合(例如,“數(shù)組”)。標識由諸如唯一地識別對象的標識號(例如,存儲器地址)之類的每個實例化對象所包括的頭部信息來實現(xiàn)。然而,對象標識具有占用空間(footprint)和性能成本,這是Java具有存儲在適當?shù)奈恢谩⒃诜椒ㄕ{(diào)用期間在不使用引用的情況下通過值傳遞、并且不包括頭部的原生類型(primitive type)的主要原因。這與引用類型相反,引用類型由指針訪問、使用在方法調(diào)用期間通過值傳遞的引用來表示、并且包括頭部。對于不具有許多字段來分攤支持標識所需的額外成本的小對象來說,支持標識的成本是最難以負擔的。

例如,考慮具有類型為整型(int)的x和y字段的Point類。在實施方式中,每個Point對象可以包括額外的對象頭部(8到16字節(jié))和引用(4到8字節(jié))的Point對象數(shù)組意味著這些8字節(jié)的數(shù)據(jù)(對于x和y整數(shù))占用20到32字節(jié)的堆空間。此外,遍歷該數(shù)組意味著對于所訪問的每個Point對象的指針解引用。這破壞了數(shù)組的內(nèi)在局部性(inherent locality)并且限制了程序性能。

程序員經(jīng)常采取比如將Point數(shù)組表示為兩個整型數(shù)組(一個用于x并且一個用于y)的技巧來避免這些成本,但是該方法犧牲了封裝性(和可維護性)只是為了補回標識的性能損失。一種方法是顯著擴大語言支持的原生的數(shù)量。然而,(如果有可能的話)可能難以預期高效地解決放在程序員面前的每個問題將需要的原生類型。因此,落在原生類型和對象的領域之間的結構體將對程序員有很大益處。

附圖說明

在附圖的圖中通過示例的方式而不是限制的方式示出了本發(fā)明,在附圖中相似的附圖標記指代相似的要素,其中:

圖1示出了可以實踐本文所描述的技術的示例性計算架構。

圖2是示出了適于實現(xiàn)本文所描述的方法和特征的計算機系統(tǒng)的一個實施例的框圖。

圖3示出了根據(jù)實施例的以框圖形式的示例性虛擬機存儲器布局。

圖4示出了根據(jù)實施例的以框圖形式的示例性幀。

圖5示出了根據(jù)實施例的用于在容器中存儲值類型的過程。

圖6示出了根據(jù)實施例的用于訪問值類型的過程流。

圖7是示出了可以實現(xiàn)本發(fā)明的實施例的計算機系統(tǒng)的框圖。

具體實施方式

在下面的描述中,出于解釋的目的,闡述了許多具體細節(jié)以便提供對本發(fā)明的深入理解。然而,顯而易見,可以在沒有這些具體細節(jié)的情況下實踐本發(fā)明。在其他實例中,公知的結構和設備以框圖形式示出,以避免不必要地混淆本發(fā)明。

本文根據(jù)以下提綱描述實施例:

1.0總體概述

2.0示例性操作環(huán)境

2.1示例性類文件結構

2.2示例性虛擬機架構

2.3加載、鏈接和初始化

3.0值類型概述

3.1用例

3.2示例性值類型特性

3.3示例性限制

3.4指針管理

3.5示例性定義

3.6示例性用法

3.7示例性實現(xiàn)細節(jié)

3.8示例性字節(jié)碼和類型描述符

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總體概述

本文所描述的技術經(jīng)常使用來自Java編程語言、Java虛擬機(“JVM”)和Java運行環(huán)境的術語和定義。然而,構想的是所描述的技術可以結合任何編程語言、虛擬機架構或運行環(huán)境來使用。因此,例如諸如“方法”之類的按Java術語描述的用辭可與諸如“函數(shù)”之類的其他用辭互換。此外,術語“方法”還與術語“類方法”或“對象方法”同義。方法是由名稱指代并且可以在使得方法的代碼被執(zhí)行的程序中的各種點處調(diào)用(援用)的一組代碼或代碼塊。

在實施例中,值類型是遵循“像類一樣編程,像整型一樣工作”原則的一種類別的聚合體。因此,像類一樣,值類型可以由程序員按照被命名的、類型成分(字段)、行為(方法)、隱私(訪問控制)、編程初始化(構造函數(shù)(constructor))等來定義。然而,像原生類型(諸如整型)一樣,值類型不包含頭部信息并且被有效地當作用戶定義的原生。因此,當可行時,值類型被存儲為扁平化的表示并且在方法之間通過值傳遞。因此,與對象相比,通過不要求指針被解引用以訪問值類型實現(xiàn)了速度改進,并且通過不要求值類型存儲頭部信息實現(xiàn)了存儲改進。然而,實施例自由地以許多方式實現(xiàn)值類型的方面,這些方式中的一些方式可以違背“像類一樣編程,像整型一樣工作”原則。因此,本文所描述的值類型的特征可以被分開實現(xiàn)、作為整體實現(xiàn)或者無限制地以任何組合實現(xiàn)。

然而,為了實現(xiàn)值類型,存在若干考慮。一個考慮是如何在源語言和/或虛擬機的指令集(當適用時)中顯現(xiàn)(surface)值類型。例如,由于值類型不包含具有標識信息的頭部,因此依賴于標識的許多特征要么對于值類型必須被禁用,要么在值類型的背景下必須被分配新含義。作為另一示例,附加的指令和/或關鍵字可以被添加到源語言/虛擬機指令集以定義和利用值類型。節(jié)3.0“值類型概述”及其相關小節(jié)一般涉及如何在源語言和/或虛擬機的指令集中顯現(xiàn)值類型的問題。

另一個考慮是如何在諸如虛擬機的運行環(huán)境之類的計算機系統(tǒng)的工作存儲器內(nèi)處理值類型的存儲。如上文提到的,旨在以扁平化的表示來存儲值類型。因此,例如如果對象具有存儲值類型的字段,則旨在將該值類型在沒有指針間接尋址(pointer indirection)的情況下存儲在適當?shù)奈恢谩W鳛榱硪皇纠?,當值類型被加載到棧幀(stack frame)中的局部變量中時,該值類型被扁平地存儲在表示局部變量的容器中。然而,因為值類型可以具有可變的尺寸,所以存在容器可能需要被調(diào)整尺寸以便容納特定的值類型的情況。這造成了性能問題,因為為容器重新分配內(nèi)存可能帶來大量開銷,尤其是當重新分配經(jīng)常被執(zhí)行的時候。

因此,在一些實施例中,實現(xiàn)優(yōu)化以對存儲值類型的成本設定界限。例如,虛擬機的驗證器可以定義若干指派規(guī)則,當接收到在容器中放置值類型的指令時檢查這些指派規(guī)則。例如,驗證器可以阻止將被分配為針對一種值類型的容器用于存儲具有不同尺寸的值類型。因此,阻止了虛擬機不斷地重新分配容器以適配不同的值類型。作為另一示例,如果值類型超出了尺寸閾值并且被確定為是不可變的,則虛擬機可以選擇在所管理的堆存儲器上存儲值類型并且替代地在容器中存儲對堆的引用。因此,阻止了虛擬機引起多次復制過大的值類型的開銷。例如,如果局部變量被放置在操作數(shù)棧上,則該局部變量可以通過引用而不是通過值被復制。然而,由于值類型是不可變的,因此對終端用戶而言,指令的行為(從語義的角度)無法與其中值類型被存儲并通過值傳遞的情況分辨開來。這可能導致訪問的時間增加,但是對于大的值類型來說,復制花費的時間量可能大大超過去除指針遍歷的益處。節(jié)5.0“存儲考慮”及其相關小節(jié)一般涉及存儲優(yōu)化和性能的問題。

在一些實施例中,值類型是不可變的,意味著值類型(至少從終端用戶的視角)不能以分段的方式更新。這類似于諸如Java之類的一些語言怎樣允許由變量保持的整數(shù)被替換,但是不向用戶提供允許整數(shù)的單個位改變值的指令。因此,在值類型的背景下,不可變性意味著值類型僅可以作為整體被替換。然而,即使當值類型為不可變時,值類型也仍然可以被存儲在可變的變量或容器中。在變量、字段或容器的背景下,不可變性暗示著由該變量或容器保持的值不能被替換(例如,被凍結)。

另一考慮是如何阻止值類型在被多個線程訪問時的撕裂。假設值類型被存儲在諸如許多虛擬機實現(xiàn)方式的堆之類的共享存儲器中,由于多個線程同時訪問值類型,因此存在競爭狀況(race condition)的風險。由于值類型旨在充當諸如原生整型之類的整個值,因此當?shù)谝痪€程試圖更新存儲值類型的容器并且第二線程在第一線程完全結束更新之前讀取該容器時,結構撕裂發(fā)生。結果,第二線程在容器中遇到部分是舊值并且部分是新值的值類型。為了阻止結構撕裂,技術被應用以使得存儲和加載操作是原子的。然而,由于值類型是用戶定義的,因此執(zhí)行原子訪問的合適方法可能基于值類型的尺寸和/或用途以及底層計算機系統(tǒng)的硬件能力而變化。例如,一些中央處理單元(CPU)支持針對各種尺寸(例如,64位、128位、256位等)的原子更新和/或事務,但是這些硬件指令不能考慮可能被用于值類型的每個尺寸。因此,因為值類型可以大于底層硬件支持的最大原子存儲器轉移,所以結構撕裂變得有可能,這是因為(例如)對4成分值的寫入可以被拆成兩個64位寫入,而該值的讀取可以被拆成兩個64位讀取。因此,如果讀取和寫入這二者同時執(zhí)行,則有可能遇到作為舊值和新值的混合的值類型。

在實施例中,使用若干技術來優(yōu)化針對值類型的原子操作。例如,如果硬件指令可用于執(zhí)行原子操作,則該指令是優(yōu)選的,因為硬件實現(xiàn)的技術與軟件實現(xiàn)的技術相比一般具有更好的性能。此外,在某些情形中,原子操作可以被繞過,諸如當被訪問的字段為不可變時。在一些實施例中,當值類型的字段被頻繁訪問時,值類型被修改以將該字段放置在由指針引用訪問的單獨的容器中。通過創(chuàng)建更新后的值的拷貝并且切換指針,可以相對快地執(zhí)行對通過指針訪問的字段的原子更新。因此,通過修改值類型的結構,當執(zhí)行原子訪問時可以獲得提高的性能。節(jié)6.0“原子操作”一般針對涉及原子操作的問題。

2.0示例性操作架構

圖1示出了可以實踐本文所描述的技術的示例計算架構100。

如圖1中所示,計算架構100包括源代碼文件101,源代碼文件101由編譯器102編譯為表示要被執(zhí)行的程序的類文件103。類文件103然后由執(zhí)行平臺112加載并且執(zhí)行,執(zhí)行平臺112包括運行環(huán)境113、操作系統(tǒng)111以及使得能夠實現(xiàn)運行環(huán)境113和操作系統(tǒng)111之間的通信的一個或多個應用編程接口(API)110。運行環(huán)境113包括虛擬機104,虛擬機104包括各種組件,諸如存儲器管理器105(其可以包括垃圾收集器)、用于檢查類文件103和方法指令的合法性的驗證器106、用于定位和建立類的存儲器中(in-memory)表示的類加載器107、用于執(zhí)行虛擬機104代碼的解釋器108以及用于產(chǎn)生優(yōu)化的機器級別代碼的即時(JIT)編譯器109。

在實施例中,計算架構100包括源代碼文件101,源代碼文件101包含以諸如Java、C、C++、C#、Ruby、Perl等之類的特定編程語言編寫的代碼。因此,源代碼文件101遵守用于相關語言的一組特定的語法和/或語義規(guī)則。例如,以Java編寫的代碼遵守Java語言規(guī)范。然而,由于規(guī)范隨時間而被更新和修訂,因此源代碼文件101可以與版本號相關聯(lián),該版本號指示源代碼文件101所遵守的規(guī)范的修訂版本。被用于編寫源代碼文件101的確切的編程語言一般不關鍵。

在各種實施例中,編譯器102把根據(jù)依照程序員的方便的規(guī)范編寫的源代碼轉換成可由特定機器環(huán)境直接執(zhí)行的機器代碼或對象代碼,或者轉換成可由能夠在多種特定機器環(huán)境上運行的虛擬機104執(zhí)行的中間表示(“虛擬機代碼/指令”),諸如字節(jié)碼。虛擬機指令可由虛擬機104以比源代碼更直接、更高效的方式執(zhí)行。將源代碼轉換為虛擬機指令包括將來自語言的源代碼功能映射到利用諸如數(shù)據(jù)結構之類的底層資源的虛擬機功能。時常地,由程序員經(jīng)由源代碼以簡單術語呈現(xiàn)的功能被轉換成更復雜的步驟,該更復雜的步驟更直接地映射到由虛擬機104駐留在其上的底層硬件支持的指令集。

一般來說,程序要么作為編譯后的程序執(zhí)行,要么作為解釋后的程序執(zhí)行。當程序被編譯時,在執(zhí)行之前代碼從第一語言被全局地轉變?yōu)榈诙Z言。由于轉變代碼的工作是提前執(zhí)行的,因此編譯后的代碼往往具有杰出的運行時性能。另外,由于在執(zhí)行之前所述轉變?nèi)值匕l(fā)生,因此可以使用諸如常量折疊、死代碼消除、內(nèi)聯(lián)等之類的技術來分析和優(yōu)化代碼。然而,取決于正被執(zhí)行的程序,啟動時間可能是顯著的。另外,插入新代碼將會要求程序離線、重新編譯和重新執(zhí)行。對于被設計為允許在程序的執(zhí)行期間插入代碼的許多動態(tài)語言(諸如Java)來說,純編譯的方法一般是不合適的。當程序被解釋時,程序的代碼在程序執(zhí)行的同時被逐行讀取并且轉換為機器級別的指令。結果,程序具有短的啟動時間(可以幾乎立刻開始執(zhí)行),但是運行中執(zhí)行轉換減弱了運行時性能。此外,由于每個指令被單獨分析,因此依賴于對程序的更全局的分析的許多優(yōu)化不能執(zhí)行。

在一些實施例中,虛擬機104包括解釋器108和JIT編譯器109(或者實現(xiàn)這二者的方面的組件),并且使用解釋技術和編譯技術的組合來執(zhí)行程序。例如,虛擬機104最初可以開始于經(jīng)由解釋器108解釋表示程序的虛擬機指令并同時追蹤關于程序行為的統(tǒng)計數(shù)據(jù),諸如虛擬機104執(zhí)行不同的代碼部分或代碼塊的頻率。一旦代碼塊超過某一閾值(它是“熱的”),則虛擬機104調(diào)用JIT編譯器109來執(zhí)行對塊的分析并且生成替換“熱”代碼塊的經(jīng)優(yōu)化的機器級別的指令以供將來執(zhí)行。由于程序往往花費其大部分時間來執(zhí)行它們的整體代碼的小部分,因此僅編譯程序代碼的“熱”部分可以提供與完全編譯的代碼相似的性能,但是沒有啟動的損失。此外,盡管優(yōu)化分析局限于被替換的“熱”塊,但是仍然存在與獨個地轉換每個指令相比大得多的優(yōu)化潛力。

為了提供清楚的示例,源代碼文件101被示為要由執(zhí)行平臺111執(zhí)行的程序的“最高級別”表示。然而,盡管計算架構100將源代碼文件101描繪為“最高級別”程序表示,但是在其他實施例中源代碼文件101可以是經(jīng)由“較高級別”編譯器接收的中間表示,該“較高級別”編譯器將不同語言的代碼文件處理成源代碼文件101的語言。為了示出清楚的示例,以下公開假設源代碼文件101遵守基于類的面向對象的編程語言。然而,這不是利用本文所描述的特征的要求。

在實施例中,編譯器102接收源代碼文件101作為輸入并且將源代碼文件101轉換成虛擬機104所期望的格式的類文件103。例如,在JVM的背景下,Java虛擬機規(guī)范的第4章定義了期望類文件103遵守的特定類文件格式。在一些實施例中,類文件103包含已經(jīng)從源代碼文件101轉換而來的虛擬機指令。然而,在其他實施例中,類文件103還可以包含其他結構,諸如標識關于各種結構(類、字段、方法等)的常量值和/或元數(shù)據(jù)的表。

以下討論將假設類文件103中的每個類文件表示在源代碼文件101中定義的(或者由編譯器102或虛擬機104動態(tài)生成的)各個“類”。然而,前面提到的假設不是嚴格的要求并且將取決于虛擬機104的實現(xiàn)方式。因此,不管類文件103的確切格式如何,仍然可以執(zhí)行本文所描述的技術。在一些實施例中,類文件103被劃分成一個或多個“庫”或“包”,其中每個“庫”或“包”包括提供相關功能的一批類。例如,一個庫可以包含實現(xiàn)輸入/輸出(I/O)操作、數(shù)學工具、密碼技術、圖形實用程序等的一個或多個類文件。此外,一些類(或者這些類內(nèi)的字段/方法)可以包括訪問限制,該訪問限制將其使用限制在特定的類/庫/包內(nèi)或者限制在具有適當許可的類內(nèi)。

2.1示例性類文件結構

圖2示出了根據(jù)實施例的以框圖形式的關于類文件200的示例性結構。為了提供清楚的示例,本公開的余下部分假設計算架構100的類文件103遵守本節(jié)中所描述的示例性類文件200的結構。然而,在實際環(huán)境中,類文件200的結構將取決于虛擬機104的實現(xiàn)方式。此外,本文所討論的一個或多個特征可以修改類文件200的結構以例如添加附加結構類型。因此,對于本文所描述的技術來說,類文件200的確切結構不是關鍵的。出于節(jié)2.1的目的,“類”或“該類”是指由類文件200表示的類。

在圖2中,類文件200包括常量表201、字段結構208、類元數(shù)據(jù)204和方法結構209。

在實施例中,常量表201是除其他功能之外還充當類的符號表的數(shù)據(jù)結構。例如,常量表201可以存儲與源代碼文件101中使用的各種識別符(諸如類型、范圍、內(nèi)容和/或位置)相關的數(shù)據(jù)。常量表201具有用于由編譯器102從源代碼文件101導出的值結構202(表示整型、長整型、雙精度型(double)、浮點型、字節(jié)型、字符串型等類型的常量值)、類信息結構203、名稱和類型信息結構205、字段引用結構206以及方法引用結構207的條目。在實施例中,常量表201被實現(xiàn)為將索引i映射到結構j的數(shù)組。然而,常量表201的確切實現(xiàn)方式不是關鍵的。

在一些實施例中,常量表201的條目包括對其他常量表201條目進行索引的結構。例如,用于表示字符串的值結構202之一的條目可以保持將其“類型”標識為字符串的標簽以及對存儲表示該字符串的ASCII字符的字符型、字節(jié)型或整型值的常量表201的一個或多個其他值結構202的索引。

在實施例中,常量表201的字段引用結構206保持對常量表201中表示定義字段的類的類信息結構203的索引以及對常量表201中提供字段的名稱和描述符的名稱和類型信息結構205的索引。常量表201的方法引用結構207保持對常量表201中表示定義方法的類的類信息結構203的索引以及對常量表201中提供方法的名稱和描述符的名稱和類型信息結構205的索引。類信息結構203保持對常量表201中保持相關類的名稱的值結構202的索引。名稱和類型信息結構205保持對常量表201中存儲字段/方法的名稱的值結構202的索引以及對常量表201中存儲描述符的值結構202的索引。

在實施例中,類元數(shù)據(jù)204包括用于類的元數(shù)據(jù),諸如版本號、常量池中的條目的數(shù)量、字段的數(shù)量、方法的數(shù)量、訪問標志(類是否是公有的(public)、私有的(private)、最終的(final)、抽象的(abstract)等)、對常量表201的類信息結構203中標識該類的一個類信息結構的索引、對常量表201的類信息結構203中標識超類(如果有的話)的一個類信息結構的索引等等。

在實施例中,字段結構208表示標識類的各個字段的一組結構。字段結構208針對類的每個字段存儲關于該字段的訪問器標志(字段是否是公有的、私有的、最終的、抽象的等)、對常量表201中保持字段的名稱的值結構202的索引、以及對常量表201中保持字段的描述符的值結構202的索引。

在實施例中,方法結構209表示標識類的各個方法的一組結構。方法結構209針對類的每個方法存儲關于該方法的訪問器標志(方法是否是靜態(tài)的、公有的、私有的、同步的等)、對常量表201中保持方法的名稱的值結構202的索引、對常量表201中保持方法的描述符的值結構202的索引、以及與如源代碼文件101中定義的方法主體對應的虛擬機指令。

在實施例中,描述符表示字段或方法的類型。例如,描述符可以被實現(xiàn)為遵守特定語法的字符串。盡管確切的語法不是關鍵的,但是下文描述了幾個示例。

在描述符表示字段的類型的示例中,描述符標識由字段保持的數(shù)據(jù)的類型。在實施例中,字段可以保持基本類型、對象或數(shù)組。當字段保持基本類型時,描述符是標識該基本類型的字符串(例如,“B”=byte(字節(jié)型)、“C”=char(字符型)、“D”=double(雙精度型)、“F”=float(浮點型)、“I”=int(整型)、“J”=long int(長整型)等)。當字段保持對象時,描述符是標識對象的類名稱的字符串(例如,“L ClassName”)。在該情況中“L”指示引用,因此“L ClassName”表示對類ClassName的對象的引用。當字段是數(shù)組時,描述符標識由數(shù)組保持的類型。例如,“[B”指示字節(jié)型的數(shù)組,其中“[”指示數(shù)組而“B”指示該數(shù)組保持字節(jié)型的基本類型。然而,由于數(shù)組可以嵌套,因此關于數(shù)組的描述符還可以指示嵌套。例如,“[[L ClassName”指示數(shù)組,在該數(shù)組中每個索引保持保持類ClassName的對象的數(shù)組。在一些實施例中,ClassName是完全限定的(fully qualified)并且包括類的簡單名稱以及類的路徑名稱。例如,ClassName可以指示文件存儲在托管類文件200的包、庫或文件系統(tǒng)中的何處。

在方法的情況中,描述符識別方法的參量和方法的返回類型。例如,方法描述符可以遵循一般形式“({ParameterDescriptor})ReturnDescriptor”,其中{ParameterDescriptor}是表示參量的字段描述符的列表,而ReturnDescriptor是標識返回類型的字段描述符。例如,字符串“V”可以被用于表示空(void)返回類型。因此,在源代碼文件101中被定義為“Object m(int I,double d,Thread t){…}”的方法匹配描述符“(I D L Thread)L Object”。

在實施例中,方法結構209中所保持的虛擬機指令包括引用常量表201的條目的操作。

使用Java作為示例,考慮下面的類:

在上面的示例中,Java方法add12and13被定義在類A中、不帶參數(shù)并且返回整數(shù)。方法add12and13的主體調(diào)用以常量整數(shù)值12和13作為參數(shù)的類B的靜態(tài)方法addTwo,并且返回結果。因此,在常量表201中,編譯器102除其他條目之外還包括與對方法B.addTwo的調(diào)用對應的方法引用結構。在Java中,對方法的調(diào)用向下編譯為JVM的字節(jié)碼中的invoke命令(在該情況中是invokestatic,因為addTwo是類B的靜態(tài)方法)。invoke命令被提供了對常量表201中與標識定義addTwo的類“B”的方法引用結構對應的索引、addTwo的名稱“addTwo”以及addTwo的描述符“(I I)I”。例如,假設前面提到的方法引用被存儲在索引4處,則字節(jié)碼指令可以表現(xiàn)為“invokestatic#4”。

由于常量表201利用承載有標識信息的結構以符號形式指代類、方法和字段,而不是利用對存儲器位置的直接引用,因此常量表201的條目被稱為“符號引用”。符號引用被用于類文件103的一個原因是因為:在一些實施例中,編譯器102不了解類一旦被加載到運行環(huán)境113中將怎樣被存儲以及將被存儲在何處。如將在節(jié)2.3中描述的,在被引用的類(以及相關結構)已經(jīng)被加載到運行環(huán)境中并且已經(jīng)被分配了具體的存儲器位置之后,最終,符號引用的運行時表示由虛擬機104解析為實際的存儲器地址。

2.2示例性虛擬機架構

圖3示出了根據(jù)實施例的以框圖形式的示例性虛擬機存儲器布局300。為了提供清楚的示例,余下討論將假設虛擬機104遵守圖3中描繪的虛擬機存儲器布局300。另外,盡管虛擬機存儲器布局300的組成部分可以被稱為存儲器“區(qū)域”,但是不要求存儲器區(qū)域是相鄰的。

在圖3示出的示例中,虛擬機存儲器布局300被劃分成共享區(qū)域301和線程區(qū)域307。

共享區(qū)域301表示存儲器中在虛擬機104上執(zhí)行的各個線程之間共享的結構被存儲的區(qū)域。共享區(qū)域301包括堆302和每個類的區(qū)域303。在實施例中,堆302表示從中分配用于類實例和數(shù)組的存儲器的運行時數(shù)據(jù)區(qū)域。在實施例中,每個類的區(qū)域303表示存儲屬于獨個類的數(shù)據(jù)的存儲器區(qū)域。在實施例中,對于每個加載的類,每個類的區(qū)域303包括表示來自類的常量表201的數(shù)據(jù)的運行時常量池304、字段和方法數(shù)據(jù)306(例如,用于保持類的靜態(tài)字段)以及表示用于類的方法的虛擬機指令的方法代碼305。

線程區(qū)域307表示存儲特定于獨個線程的結構的存儲器區(qū)域。在圖3中,線程區(qū)域307包括表示由不同線程利用的每個線程結構的線程結構308和線程結構311。為了提供清楚的示例,圖3中描繪的線程區(qū)域307假設兩個線程正在虛擬機104上執(zhí)行。然而,在實際環(huán)境中,虛擬機104可以執(zhí)行任何任意數(shù)量的線程,其中線程結構的數(shù)量相應地縮放。

在實施例中,線程結構308包括程序計數(shù)器309和虛擬機棧310。類似地,線程結構311包括程序計數(shù)器312和虛擬機棧313。在實施例中,程序計數(shù)器309和程序計數(shù)器311存儲正由它們各自的線程執(zhí)行的虛擬機指令的當前地址。因此,當線程逐句通過(step through)指令時,程序計數(shù)器被更新以維護對當前指令的索引。在實施例中,虛擬機棧310和虛擬機棧313各自存儲它們各自的用于保持局部變量和部分結果的幀(frame),并且還被用于方法調(diào)用和返回。

在實施例中,幀是用于存儲數(shù)據(jù)和部分結果、返回用于方法的值以及執(zhí)行動態(tài)鏈接的數(shù)據(jù)結構。每次調(diào)用方法時就創(chuàng)建新幀。當使得幀被生成的方法完成時,幀被銷毀。因此,當線程執(zhí)行方法調(diào)用時,虛擬機104生成新幀,并且將該幀推到與線程相關聯(lián)的虛擬機棧上。當方法調(diào)用完成時,虛擬機104將方法調(diào)用的結果傳遞回前一幀并且使當前幀出棧。在實施例中,對于給定的線程,在任何時間點處有一個幀是活動的。該活動的幀被稱為當前幀,使得生成當前幀的方法被稱為當前方法,而當前方法所屬的類被稱為當前類。

圖4示出了根據(jù)實施例的以框圖形式的示例性幀400。為了提供清楚的示例,余下討論將假設虛擬機棧310和虛擬機棧313的幀遵守幀400的結構。

在實施例中,幀400包括局部變量401、操作數(shù)棧402和運行時常量池引用表403。

在實施例中,局部變量401被表示為各自保持諸如布爾型、字節(jié)型、字符型、短整型、整型、浮點型、引用型等之類的值的變量的數(shù)組。此外,諸如長整型或雙精度型之類的一些值類型可以由數(shù)組中的多于一個條目表示。局部變量401被用于在方法調(diào)用時傳遞參數(shù)以及存儲部分結果。例如,當響應于調(diào)用方法而生成幀400時,參數(shù)可以被存儲在局部變量401內(nèi)的預定位置中,諸如與調(diào)用中的第一個到第N個參數(shù)對應的索引1-N。

在實施例中,當虛擬機104創(chuàng)建幀400時,操作數(shù)棧402默認是空的。然后虛擬機104供應來自當前方法的方法代碼305的指令以將來自局部變量501的常量或值加載到操作數(shù)棧502上。其他指令從操作數(shù)棧402取出操作數(shù)、對它們進行操作并且將結果推到操作數(shù)棧402上。此外,操作數(shù)棧402被用于準備要被傳遞到方法的參數(shù)以及接收方法結果。例如,在發(fā)出對方法的調(diào)用之前,正被調(diào)用的方法的參數(shù)可以被推到操作數(shù)棧402上。然后虛擬機104生成用于方法調(diào)用的新幀,其中前一幀的操作數(shù)棧402上的操作數(shù)出棧并且被加載到新幀的局部變量401中。當被調(diào)用的方法終止時,新幀從虛擬機棧出棧并且返回值被推回前一幀的操作數(shù)棧402上。

盡管使用諸如“數(shù)組”和/或“棧”之類的數(shù)據(jù)結構來提及局部變量401和操作數(shù)棧402,但是對用于實現(xiàn)這些元素的數(shù)據(jù)結構的類型沒有限制。另外,關于局部變量401和操作數(shù)棧402在此提及的數(shù)據(jù)結構涉及數(shù)據(jù)結構的高級別表示。實施例可以使用各種較低級別的存儲機制來實現(xiàn)這些數(shù)據(jù)結構,諸如將局部變量401和/或操作數(shù)棧402的一個或多個值存儲在執(zhí)行虛擬機104的機器硬件的中央處理單元(CPU)的一個或多個寄存器中。較低級別的指令可以引用對于較高級別的指令來說透明的一個或多個較低級別的存儲機制。盡管可以使用各種較低級別的存儲機制(這些較低級別的存儲機制都不是由較高級別的指令指定的)來實現(xiàn)較高級別的指令,但是較低級別的指令引用用于實現(xiàn)較高級別的指令的一個或多個特定存儲機制。

在實施例中,運行時常量池引用表403包含對當前類的運行時常量池304的引用。運行時常量池引用表403被用于支持解析。解析是這樣的過程:通過該過程,常量池304中的符號引用被翻譯為具體的存儲器地址,按照需要加載類以解析尚未定義的符號并且將變量訪問翻譯成與這些變量的運行時位置相關聯(lián)的存儲結構中的合適的偏移。

2.3加載、鏈接和初始化

在實施例中,虛擬機104動態(tài)地加載、鏈接和初始化類。加載是尋找具有特定名稱的類并且在運行環(huán)境113的存儲器內(nèi)創(chuàng)建來自該類的相關聯(lián)的類文件200的表示的過程。例如,在虛擬機存儲器布局300的每個類的區(qū)域303內(nèi)為該類創(chuàng)建運行時常量池304、方法代碼305以及字段和方法數(shù)據(jù)306。鏈接是采用類的存儲器中表示并且將其與虛擬機104的運行時狀態(tài)組合以使得類的方法可以被執(zhí)行的過程。初始化是執(zhí)行類構造函數(shù)以設置類的字段和方法數(shù)據(jù)306的起始狀態(tài)和/或為被初始化的類在堆302上創(chuàng)建類實例的過程。

以下是可以由虛擬機104實現(xiàn)的加載、鏈接和初始化技術的示例。然而,在許多實施例中步驟可以交錯,以使得初始類被加載,然后在鏈接期間第二個類被加載以解析在第一個類中發(fā)現(xiàn)的符號引用,這又使得第三個類被加載,等等。因此,通過加載、鏈接和初始化的階段的進程可以根據(jù)類而有所不同。此外,一些實施例可以延遲(“懶惰地”執(zhí)行)加載、鏈接和初始化過程的一個或多個功能直至該類被實際要求。例如,方法引用的解析可以被延遲直至調(diào)用被引用的方法的虛擬機指令被執(zhí)行。因此,對于每個類何時執(zhí)行步驟的確切時機在實施方式之間可以差別很大。

為了開始加載過程,虛擬機104通過調(diào)用加載初始類的類加載器107而啟動。用于指定初始類的技術將隨著實施例不同而變化。例如,一種技術可以使虛擬機104在啟動時接受指定初始類的命令行參數(shù)。

為了加載類,類加載器107解析對應于類的類文件200并且確定類文件200是否為格式良好的(滿足虛擬機104的語法期待)。如果類文件200不是格式良好的,則類加載器107生成錯誤。例如,在Java中,可能以異常的形式生成錯誤,該異常被拋給異常處理器以供處理。否則,類加載器107通過在每個類的區(qū)域303內(nèi)分配用于該類的運行時常量池304、方法代碼305以及字段和方法數(shù)據(jù)306來生成該類的存儲器中表示。

在一些實施例中,當類加載器107加載類時,類加載器107還遞歸加載被加載的類的超類。例如,虛擬機104可以確保:在進行對于特定類的加載、鏈接和初始化過程之前,該特定類的超類被加載、鏈接和/或初始化。

在鏈接期間,虛擬機104驗證類、準備類并且執(zhí)行類的在運行時常量池304中定義的符號引用的解析。

為了驗證類,虛擬機104檢查類的存儲器中表示在結構上是否是正確的。例如,虛擬機104可以檢查除了泛型類對象之外的每個類具有超類、檢查最終類不具有子類以及最終方法沒有被重載、檢查當前類是否具有對于常量池304中所引用的類/字段/結構的正確的訪問許可、檢查方法的虛擬機104代碼將不會引發(fā)意外行為(例如,確保跳轉指令不會使虛擬機104超出方法的末尾),等等。在驗證期間執(zhí)行的確切檢查取決于虛擬機104的實現(xiàn)方式。在一些情況中,驗證可以導致附加的類被加載,但是在繼續(xù)進行之前不一定要求這些類還被鏈接。例如,假設類A包含對類B的靜態(tài)字段的引用。在驗證期間,虛擬機104可以檢查類B以確保所引用的靜態(tài)字段實際存在,這可能導致類B的加載,但不一定導致類B的鏈接或初始化。然而,在一些實施例中,某些驗證檢查可以被推遲至較晚的階段,諸如在符號引用的解析期間被檢查。例如,一些實施例可以推遲檢查對于符號引用的訪問許可直至這些引用被解析。

為了準備類,虛擬機104將位于該類的字段和方法數(shù)據(jù)306內(nèi)的靜態(tài)字段初始化為默認值。在一些情況中,將靜態(tài)字段設置為默認值可以與運行該類的構造函數(shù)不同。例如,驗證過程可以在初始化期間將靜態(tài)字段清零或者將靜態(tài)字段設置為構造函數(shù)希望這些字段具有的值。

在解析期間,虛擬機104根據(jù)類的運行時常量池304中所包括的符號引用來動態(tài)地確定具體的存儲器地址。為了解析符號引用,虛擬機104利用類加載器107來加載符號引用中識別的類(如果還未加載)。一旦該類被加載,則虛擬機104了解所引用的類及其字段/方法的每個類的區(qū)域303內(nèi)的存儲器位置。然后虛擬機104將符號引用替換為對所引用的類、字段或方法的具體的存儲器位置的引用。在實施例中,虛擬機104高速緩存解析以便在當虛擬機104處理另一個類時遇到相同的類/名稱/描述符的情況下重新使用。例如,在一些情況中,類A和類B可以調(diào)用類C的同一方法。因此,當針對類A執(zhí)行解析時,該結果可以被高速緩存并且在類B中的相同符號引用的解析期間被重新使用以降低開銷。

在一些實施例中,在鏈接期間解析符號引用的步驟是可選的。例如,實施例可以以“懶惰的”方式執(zhí)行符號解析,從而延遲解析的步驟直至需要所引用的類/方法/字段的虛擬機指令被執(zhí)行。

在初始化期間,虛擬機104執(zhí)行類的構造函數(shù)以設置該類的起始狀態(tài)。例如,初始化可以初始化類的字段和方法數(shù)據(jù)306以及在由構造函數(shù)創(chuàng)建的堆302上生成/初始化任何類實例。例如,用于類的類文件200可以指定特定方法是用于設立起始狀態(tài)的構造函數(shù)。因此,在初始化期間,虛擬機104執(zhí)行該構造函數(shù)的指令。

在一些實施例中,虛擬機104通過最初檢查字段/方法在所引用的類中是否被定義來執(zhí)行對字段和方法引用的解析。否則,虛擬機104針對所引用的方法/字段遞歸搜索所引用的類的超類直至字段/方法被定位或到達最高級別的超類,在到達最高級別的超類的情況下生成錯誤。

3.0值類型概述

在一些實施例中,虛擬機104提供許多不同的方式來創(chuàng)建聚合類型。例如,虛擬機104可以提供具有標識的異構聚合(例如,經(jīng)由“類”)和具有標識的同構聚合(例如,經(jīng)由“數(shù)組”)。值類型表示異構的并且沒有標識的另一類聚合。因此,類似于原生類型(諸如字節(jié)型、短整型、整型、長整型、浮點型、雙精度型、字符型和布爾型),如果兩個存儲器區(qū)域包含相同的值類型,則這些存儲器區(qū)域中的數(shù)據(jù)不能被區(qū)分。這與在一些實施例中各自包含具有諸如對象的存儲器地址之類的唯一標識號的頭部信息的類對象相反。對象標識具有占用空間和性能成本,這是與許多其他面向對象的語言不同,Java具有原生類型的主要原因。這些成本對于不具有許多字段來分攤額外成本的小對象來說是非常難以負擔的。

在一些實施例中,在占用空間方面,具有標識的對象被分配在堆302上、具有一個或多個字的對象頭部并且(除非死亡,否則)具有指向它們的一個或多個指針。在性能方面,每個相異的實例可以被分配在堆302上并且即使對象僅包含單個字段(例如,java.lang.Integer),每個訪問也包括相關的加載(指針遍歷)以到達“載荷”。另外,在Java中,對象頭部支持包括Object.getClass、Object.wait和System.identityHashCode的許多基于標識的操作。

對象標識用來支持可變性,其中對象的狀態(tài)可以是可變的,但是維持相同的內(nèi)部對象。例如,對象的字段可以被修改,但是盡管字段的值發(fā)生改變,頭部信息仍然將對象識別為“相同的”。另外,在一些實施例中,對象標識還用來支持多態(tài)性。然而,許多編程慣用語法(idiom)不要求標識,并且由于不付出存儲器占用空間、局部性和標識的優(yōu)化懲罰而受益。盡管有重大的嘗試,但是許多虛擬機在解決標識對于程序是否有意義方面仍然較差,并且因此可能悲觀地對于不需要標識的許多對象支持標識。

在一些實施方式中,甚至名義上無狀態(tài)的(具有所有最終字段的)對象可以即使在高度優(yōu)化的代碼中使其標識隨時被追蹤,以免對象被用作同步的手段或者由依賴于標識的任何其他機制使用。該內(nèi)在的“有狀態(tài)性”妨礙許多優(yōu)化。在一些情況中,逃逸分析(escape analysis)技術有時可以減輕這些成本,但是這些技術在代碼復雜性面前是脆弱的并且在分開編譯的情況下幾乎完全失效。

運行示例:Point(點)

考慮Point類:

即使Point是不可變的,虛擬機104也不一定知道Point對象的標識將從來不被使用(例如,出于同步的目的將對象用作內(nèi)部鎖)。結果,Point被表示為關于x和y的“箱”對象。在一種實現(xiàn)方式中,Point對象的數(shù)組包括額外的對象頭部(8到16字節(jié))和引用(4到8字節(jié)),從而意味著這些8字節(jié)的數(shù)據(jù)(用于x和y整型)占用20到32字節(jié)的堆空間,而迭代該數(shù)組意味著對于所訪問的每個Point對象的指針解引用。這破壞了數(shù)組的內(nèi)在局部性并且限制了程序性能(更不用說分配帶來了垃圾收集器的工作)。程序員通常借助于如將點數(shù)組表示為兩個整型數(shù)組的技巧來避免這些成本,但是這犧牲了封裝性(和可維護性)只是為了補回標識的性能損失。另一方面,如果Point可以用與諸如整型之類的原生類型相同的方式表示,則虛擬機104可以在寄存器中存儲Point、將它們推到棧上、遍歷具有局部性的數(shù)組以及使用少得多的存儲器,而不損失封裝性。

在實施例中,值類型表示沒有標識的由用戶定義的聚合類型,其可以以源代碼文件101和虛擬機104的指令集的語言中顯現(xiàn),從而在不犧牲封裝性的情況下支持存儲器高效的和局部性高效的編程慣用語法。在實施例中,值類型是可以包含原生類型、引用類型或者甚至其他值類型的異構聚合。

在一些實施例中,例如在Java中,用于類的許多定義和封裝機構可以被用于容易且安全地建立基于新的值類型結構體的數(shù)據(jù)結構。例如,值類型可以被當作特殊標記的并且受限的類定義的形式。然而,同時,值類型對于虛擬機104的用戶來說(在語義的意義上)僅僅充當新型的原生。

如將在下面的節(jié)中探索的,盡管值類型有用地類似于類,但是(像原生那樣)在值類型和引用類型之間做出清楚且系統(tǒng)的區(qū)分是有用的。因此,在一些實施例中,新的指令被添加到虛擬機104的指令集以創(chuàng)建、發(fā)布和/或修改值類型。然而,在其他實施例中,當前指令被重載,以便根據(jù)指令是否對引用、原生類型和/或值類型操作而執(zhí)行不同的功能。

3.1用例

在實施例中,值類型可以被引入到虛擬機104以支持許多特征,這些特征在使用基于標識的聚合的情況下可能不存在或者是以次優(yōu)方式實現(xiàn)的。然而,使用值類型可以高效地實現(xiàn)以下示例。一些示例包括:

數(shù)值(numeric)。諸如JVM之類的一些虛擬機僅提供有限數(shù)量的高效數(shù)值類型;如果使用這些數(shù)值類型不能高效地解決問題,則必須替代地使用具有標識的聚合(以及相關聯(lián)的開銷)。比如復數(shù)、擴展精度的整數(shù)或無符號整數(shù)以及十進制(decimal)類型之類的數(shù)值類型是廣泛有用的,但是僅可以由原生和/或對象類來近似(有損于類型安全性、封裝性和/或性能)。

本地類型(native type)。現(xiàn)代處理器支持各種各樣的本地數(shù)據(jù)類型,并且(像數(shù)值那樣)它們中的僅僅一些被直接映射為虛擬機所支持的原生。這使得編寫直接編譯為諸如向量指令之類的包含本地類型的指令的代碼是困難的或者不可能的。

代數(shù)數(shù)據(jù)類型。使用對象箱可以實現(xiàn)像Optional<T>或Choice<T,U>那樣的數(shù)據(jù)類型。然而,就小的無標識的聚合而言,許多這樣的類型(尤其是像元組那樣的產(chǎn)品類型)具有自然的表示。單元類型(空類似物(void-like)和度量二者)對于表示代數(shù)數(shù)據(jù)類型有時也是有用的,但前提是它們的占用空間開銷可以被顯著降低或被驅使為零。

元組。值的元素可以自身被當作值并且不一定需要對象箱。

游標(cursor)。迭代器或其他游標在復制數(shù)據(jù)結構中并且不一定需要對象箱。此外,(所管理的和/或本地的)數(shù)據(jù)結構的客戶機可以在保持完整封裝性和類型安全性的情況下繞過數(shù)據(jù)結構中的迭代器和其他“智能指針”。

3.2示例性值類型特性

在一些實施例中,在虛擬機104級別處的值類型設施提供以下有益特性中的一個或多個:

標量化。在一些實施例中,值類型的實例可以被定期分解為它們的成分并且存儲在寄存器或者棧(諸如虛擬機棧310)中,而不是在堆302上。當作為包含對象的部分被存儲在堆302中時,虛擬機104可自由地使用值類型的扁平化的、無指針的表示。

包裝(wrapping)。在一些實施例中,值類型具有拆箱表示和裝箱表示這二者。拆箱表示在可行的情況下被使用以降低開銷;裝箱表示被用于與需要引用類型的API的互操作性。與例如Java中現(xiàn)有的原生包裝器不同,裝箱表示可以從值類型的描述自動生成。例如,每個值類型可以使用類文件來定義,并且虛擬機104使用該類文件來自動生成表示用于值類型的箱對象的新的類文件。作為另一示例,源代碼文件101中定義的值類型由編譯器102編譯為用于值類型的分開的類文件和值類型的裝箱形式。作為又一示例,值類型和值類型的裝箱形式這二者可以共享同一類文件,但是虛擬機將取決于上下文以不同方式對待值類型的使用。

行為。在一些實施例中,值類型不僅僅是數(shù)據(jù)的元組;它們還可以以方法的形式定義行為。例如,復數(shù)值類型的定義可以定義用于執(zhí)行復數(shù)運算的方法。然后如果硬件原生是可用的(比如對于128位的數(shù)值),則虛擬機104可以選擇內(nèi)部化該行為。類似地,數(shù)據(jù)結構游標可以定義工廠方法和訪問方法,同時保持其成分值被安全地封裝。諸如Java中的toString和equals之類的實用程序方法(utility method)可以被強加于值類,但不一定如此。在一些實施例中,實用程序方法能夠逐個值類型地定制。

名稱。諸如JVM類型系統(tǒng)之類的一些類型系統(tǒng)幾乎全部是標稱的(nominal),而不是結構的。類似地,在一些實施例中,值類型的成分可以通過名稱識別,而不是僅通過元素號識別。(這使得值類型更像記錄而不是元組)。

互操作性。在諸如JVM之類的一些虛擬機中,存在針對具有值對應物的泛型對象的若干操作,諸如equals、hashCode和toString。在一些實施例中,虛擬機(在缺乏來自值類型的作者的指令的情況下)按成分實現(xiàn)這些方法。除了對象(Object)之外,諸如Comparable(可比較型)之類的其他類型還可以與合適的值類型互操作,從而向諸如TreeSet<UnsignedInteger>之類的類型打開大門。

封裝性。在一些實施例中,值類型具有私有成分,正如對象具有私有字段。這使得例如安全的外部(foreign)“指針”或游標成為可能。值類型可以被配置為阻止?jié)撛诘墓粽咄ㄟ^提取私有成分或通過合法操作的勉強組合造出非法值來摧毀封裝性。

可驗證性。在一些實施例中,虛擬機104的指令集中的對于值類型的支持是能夠被驗證器106驗證的。

變量。在一些實施例中,諸如字段、數(shù)組元素、局部變量和方法參數(shù)之類的變量類型都被配置為保持值類型。此外,方法被配置為返回值類型。此外,修飾符(諸如Java中的final和volatile)可以被應用于值類型以實現(xiàn)它們的常規(guī)效果。

數(shù)組。在一些實施例中,值類型的數(shù)組被打包(packed),非間接地、類似于原生的數(shù)組。這不一定意味著數(shù)組本身被打包在其他對象內(nèi)部。因此,數(shù)組可以保持值類型元素的扁平化表示,但是如果數(shù)組是對象的字段,則對象可以存儲可被分配在堆302上的數(shù)組的指針。

扁平化。值類型提供了用于表達具有較少指針間接的數(shù)據(jù)結構的自然方式。因此,使用值類型來使數(shù)據(jù)扁平化允許虛擬機104更高效地布置一些數(shù)據(jù)結構。

3.3示例性限制

由于值類型不具有標識,因此存在某些操作,一些實施例可以選擇不允許對值類型進行這些操作或者為這些操作分配新的含義以供在值類型的背景下使用。在一些實施例中,對值類型的限制在虛擬機104中被實現(xiàn)為供驗證器106遵循的附加規(guī)則。因此,如果類內(nèi)的方法包含違背規(guī)則的代碼,則生成異?;蝈e誤。以下是一些示例:

鎖定。為了支持諸如在Java語言中執(zhí)行的同步,對象有時被用作經(jīng)同步的語句的鎖對象。在一些實施例中,由于缺乏對于該特征所期待的頭部信息,因此虛擬機104不允許針對這些語句使用值類型。此外,在一些實施例中,虛擬機104不允許針對值類型調(diào)用與同步相關的方法。例如,Java中的wait(等待)和notify(通知)方法。

標識比較。(在Java中)針對對象的“==”操作符執(zhí)行標識比較,但是針對原生,該操作符執(zhí)行按位比較。由于值類型不一定具有指針,因此該操作符不適用于值類型。在一些實施例中,通過遞歸地執(zhí)行“==”操作(最終基于較低級別的對象/原生來評估)、調(diào)用equals方法和/或執(zhí)行按位比較來執(zhí)行解釋針對值類型的諸如“==”之類的操作符。

標識散列碼。諸如經(jīng)由Java中的System.identityHashCode之類的用于對象的基于標識的散列碼不適用于值類型。做出對象的基于標識的區(qū)分的、像序列化那樣的內(nèi)部操作要么不適用于值類型(由于它們不適用于原生),要么會使用由值類型定義的單獨的散列碼方法供應的基于值的區(qū)分。例如,按成分的散列計算可以被還原為默認。然而,當值類型的成分是私有的時,這可能泄露可被攻擊使用的信息。

克隆。在一些實施例中,虛擬機104將諸如Java中的Clone方法之類的克隆解釋為對于值類型的標識轉變。

終止化(finalization)。在一些實施例中,對于值類型的終止化是不允許的,因此在許多實施例中對值類型的終止化將沒有用處(但是值類型可以保持自身可終止化的引用類型的成分)。

以上限制中的許多限制對應于Java中針對所謂的基于值的類的限制。實際上,在實施例中,每個值類型的裝箱形式是基于值的類。

在一些實施例中,虛擬機104對值類型做出“軟”限制以確保值類型在存儲空間和/或成分數(shù)量方面不會“太大”。由于值類型通過值來傳遞,因此隨著成分數(shù)量增加,復制許多成分的開銷越來越可能壓倒通過移除指針和對象頭部的開銷而獲得的任何節(jié)省。由于類對象是使用指針通過引用來傳遞,因此大組的成分值可以可替代地使用類來建模。

在一些實施例中,值類型的精心構思的使用通過省略對象指針和頭部以及定期通過值傳遞成分來獲得性能和復雜度的益處。具有少量成分的值類型通常整齊地匹配大多數(shù)當前的中央處理單元(CPU)(其對寄存器文件的尺寸具有相對較小的限制)的能力。當超過這些限制時,一些實施例中的虛擬機104具有將值類型分散到棧(諸如虛擬機棧310/313)和/或所管理的堆302存儲器上的靈活性。

在一些實施例中,取決于值類型的尺寸和/或值類型是否在不能被修改的容器中,虛擬機104在通過值傳遞值類型或通過引用傳遞值類型之間切換。在后面的節(jié)中以更多細節(jié)探索該特征。

3.4指針管理

當使用值類型的扁平化表示時,值類型不被指針訪問或者這種指針在虛擬機104實現(xiàn)內(nèi)對用戶隱藏。因此,即使虛擬機104在底層使用指針,虛擬機104也確保從用戶的視角來看值類型遵循通過值傳遞的行為。在一些實施例中,某些附加操作也是虛擬機104不允許的或者被虛擬機104分配新的含義。

空值(null)。空值是每個引用類型的有效值,其意味著“沒有實例”。然而,在值類型的背景下,空值可能是不適用的,這與在大多數(shù)語言中空值通常不適用于原生大致相同。因此,在一些實施例中,對于值類型來說被指派為空值以及與空值相比較是不允許的。然而,該限制將不適用于值類型的裝箱形式,其中將值類型裝箱的容器對象可以保持空值并且可以與空值相比較。

副作用。盡管包含整個值的變量可以被重新指派為不同的值,但是值的單獨部分通常不受到分段的副作用的影響,就好像它們通過對于該值的指針被訪問一樣。因此,整數(shù)可以從2被更新到3,但是在一些實施例中用戶被限制為整個值指派。結果,不向用戶提供可以改變2的最低位以將該值改變?yōu)?的代碼指令。諸如Java之類的某些語言在該方向上給出的是像intval|=1一樣的復合指派操作。此外,在第一變量處將值從2改變?yōu)?不會導致其他地方的第二變量變成3(當兩個變量都指向值被改變的同一存儲器位置時會出現(xiàn)此情況)。結果,在一些實施例中,(從用戶的角度來看)虛擬機104阻止了分段的副作用。然而,盡管從用戶的視角來看,值類型看上去是作為整體被替換(作為不可變性的性質(zhì))并且不會導致對于其他變量的副作用(作為扁平性的性質(zhì)),但是在一些實施例中在底層虛擬機104可以執(zhí)行違背該性質(zhì)的優(yōu)化。例如,盡管在語義上代碼表現(xiàn)的就像Point A被Point B完整地替換一樣,但是在底層,虛擬機104可以僅替換不同的成分以作為優(yōu)化的形式。作為另一示例,假如在語義上虛擬機104諸如通過僅在值類型不能改變的(例如,值類型是最終的)情況下執(zhí)行該優(yōu)化來阻止副作用,則在值類型較大的情況中,指針可以被用于最小化復制開銷。

在一些實施例中,語言允許通過指針訪問值類型,多達并且包括成分變化。在這種實施例中,該概念的復雜度協(xié)助本地數(shù)據(jù)結構以及虛擬機104數(shù)據(jù)。

引用轉換。在一些實施例中,像原生類型那樣,值類型可以被裝箱以便被用作引用。因此,在一些實施例中,虛擬機104具有用于隱式地對值類型進行裝箱和拆箱的規(guī)則,類似于Java當前怎樣執(zhí)行用于原生值的裝箱和拆箱。例如,通過基于上下文在整型和相應的Integer(整數(shù))值類之間自動轉換。

指針多態(tài)性。在一些實施例中,對象并入運行時類型信息,方法可以是虛擬的,類型可以在運行時被測試,以及(許多)靜態(tài)引用類型可以在運行時指向一系列具體的子類。在這種實施例中,由于指針變量盡管具有固定的尺寸但是可以指代任何尺寸和類型的數(shù)據(jù),因此前面提到的特征起作用。由于值類型沒有頭部來承載類型信息并且被設計為被扁平化到它們的包含對象中,因此值類型(在一些實施例中)不能被動態(tài)地類型測試并且不能具有可變的尺寸。結果,在一些實施例中,虛擬機104阻止子類化(sub-classing),因為該特征對于值類型沒什么用處。然而,諸如Java中的Comparable接口之類的抽象的超類和接口仍然可以被使用,因為這些結構體不能被分開實例化。在一些實施例中,值類型實現(xiàn)頭部信息的縮減集合,而不是沒有頭部信息,諸如包括尺寸數(shù)據(jù)以支持可變尺寸,但是不包括用于實現(xiàn)標識特征的諸如標識號(例如,對象的存儲器地址)之類的其他信息。

反射(reflection)。作為指針多態(tài)性的極端情況,在諸如Java之類的語言中,任何對象可以被轉換為頂級類型Object并且可以針對它的字符串表示、它的類、它的字段和字段值的集合等等而被檢查。由于在一些實施例中值類型不支持超類,因此虛擬機104可以禁用轉換值類型并且因此還禁用反射。然而,在一些實施例中,值類型的方法可以包括創(chuàng)建與從Object類型生成的字符串表示類似的字符串表示的方法。

原子性。指針提供了到其對象(可以原子地改變)的訪問路徑。因此,競爭的線程觀察到舊對象或新對象,而不是二者的混合。相比之下,多字段值可能經(jīng)受數(shù)據(jù)競爭的,在數(shù)據(jù)競爭中競爭的線程可能觀察到新字段值和舊字段值的混合。在當前的語言中,在長整型和雙精度型類型的情況下該“結構撕裂”問題有時可以作為極端情況被觀察到,但是在值類型的情況下該問題更加急迫,因為它可以嚴重地損害封裝性。在一些實施例中,虛擬機104在類型使用位置和類型定義位置這二者處按照請求供應原子性。這類似于諸如Java之類的語言在在長整型和雙精度型變量被聲明為易變的情況下如何在類型使用站點處按照請求供應原子性。在當前硬件中保證原子性的成本足夠大以致于對于不要求原子性或僅要求某些變量具有原子性的程序,始終要求原子性可能導致大量不必要的開銷。精確的折衷跨平臺變化。

3.5示例性定義

在一些實施例中,值類型的一些特性是類常見的:一批經(jīng)命名的、類型成分(字段)、行為(方法)、隱私(訪問控制)、編程初始化(構造器)等。因此,在一些實施例中,使用特殊標記的類文件來定義值類型。然而,虛擬機104可以經(jīng)由驗證器106對這些類文件施加特殊的規(guī)則,諸如在先前的節(jié)中所描述的限制。類似地,用于值類型的語法元素可以被精心設計以便看上去類似于源語言中的寫類。

在諸如Java之類的一些語言中,存在采取該方法的先例,諸如使用類文件103來表示接口,因為這些接口還與普通類有相似之處。除了模式位和小語法的附加之外,在一些實施例中,接口的二進制可以與適當?shù)念惖亩M制相同,除了接口具有附加的語法和語義限制。類似地,值類型可以在源代碼文件101中定義并且使用語法的小改變來寫,但是具有由驗證器106應用于所得到的類文件103的附加限制。

通過使用示例性語法,之前提供的Point示例可以被重寫為如下的值類型:

上面的示例和引用等價物之間的語法區(qū)別從將結構體標記為值類型而不是適當?shù)念惖年P鍵字_ByValue開始。然而,這僅是示例性的語法,將結構體標記為值類型的任何方式是容許的,諸如通過關鍵字、符號或任何其他語法來標記。此外,諸如字段、結構體和/或方法之類的用于源語言的相同的編碼慣用語法可以被重復使用以將這些值/行為添加到值類型的定義。在一些實施例中,如果用戶在源代碼文件101中未提供實用程序方法(并且語言允許該省略),虛擬機104或編譯器102填補某些實用方法(諸如按成分的hashCode、equals或toString)。

如果另一個類聲明類型Point的字段,則虛擬機104將分配用于在托管對象中的x和y成分的存儲,而不是對Point箱的引用。這可以被視為對象內(nèi)聯(lián)或扁平化。類似地,Point的數(shù)組將被布局為交替的x和y值的經(jīng)打包的數(shù)組,而不是對存儲x和y值對的容器的一系列引用。

在一些實施例中,由于與類相似地使用特征和語法來向用戶暴露值類型,因此值類型的定義對于源語言的程序員來說立刻是清楚的。然而,在各種實施例中不適用于值類型的一些熟悉的特征(諸如Java中的extends或protected)可能是不適用的。因此,如果用戶嘗試在值類型的定義中包括這些屬性,則虛擬機104的編譯器102或驗證器106拋出異?;蛏慑e誤。

在一些實施例中,源語言已經(jīng)具有表達限制的關鍵字或其他機制,諸如子字段在構造之后的不可變性。例如,Java中的final關鍵字。因此,如果用戶不再使用final關鍵字,則編譯器102可以提供解釋該關鍵字必需的錯誤或者隱式地將關鍵字添加到所生成的類文件。此外,在一些實施例中,如果final屬性丟失,則虛擬機104隱式地將final屬性添加到所生成的類文件,或者將該屬性當作已經(jīng)被設置。

3.6示例性用法

前一節(jié)描述了值類型可以如何以與類相同的方式編碼,因此下一個問題是在虛擬機104中如何定義行為以提供好像值類型是原生那樣的對待。下面是Point類的一些示例性使用:

在這些示例中,Point可以是字段、參數(shù)、局部變量或者返回值。在所有這些情況中,在一些實施例中虛擬機104將Point的成分放置在獨立地管理的位置中,諸如機器寄存器。displace方法返回新的Point值。在一些實施例中,虛擬機104通過值而不是通過(不可見的)引用來返回Point。

在一些實施例中,像原生那樣,值類型可以引導重載。這里是與上面兼容的用于stringValueOf的一些重載:

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

第一,用于成員選擇的點語法適用于值類型,如p.x或p.equals。諸如Java之類的一些語言中的原生根本不支持點語法。在一些實施例中,使用值類型來替換或補充表示原生的值類(諸如整數(shù)(Integer)),從而為針對在一些情況中是標準原生的類型(諸如整型、浮點型、雙精度型等)應用方法打開大門。

第二,在一些實施例中,虛擬機104不提供對于諸如Point之類的由用戶定義的值類型的文本的支持。替代地,定義的構造函數(shù)被調(diào)用以設置成分的值。在一些實施例中,為了確保封裝性,按成分的值創(chuàng)建除非由合適的構造函數(shù)提供,否則不被虛擬機104允許。上面的示例使用關鍵字__MakeValue來標記上面的兩個位置:新的Point值被創(chuàng)建的位置以及這種構造函數(shù)被調(diào)用的位置。然而,替代的語法還可以被用于表示值類型構造函數(shù),諸如“new Point”、“Point”以及空字符串。類似地,一些實施例不提供對于用于值類型的編譯時常量的支持。在其他實施例中,虛擬機104提供對于用戶定義的文本和常量表達式的支持。因此,在一些實施例中從被執(zhí)行以建立常量表達式的編譯時代碼構建用戶定義的操作符。

第三,用于諸如Java之類的一些語言的內(nèi)置操作符是利用原生工作的主要方式,但是在一些實施例中這些內(nèi)置操作符不適用于Point。然而,用戶定義的操作符可以被用于提供功能等價物。一些例外可能是作用于每個種類的值的操作符,諸如關系操作符(==和?。?和字符串串接(+)。字符串串接可能是棘手的,因為在一些實施例中字符串串接在值類型駐留的類和原生類型之間的區(qū)分處被精確地精妙地重載。例如,如許多Java程序員通過試錯法(trial and error)發(fā)現(xiàn)的,表達式("a"+1)+2和"a"+(1+2)具有不同的結果,因為第一個表達式首先轉換為字符串從而形成“a12”,而第二個表達式在加法后轉換為字符串從而形成“a3”。

在一些實施例中,關系操作符被當作用于判等方法(類似于Java中的equals)的別名。另外,低級別的按位判等是另一種候選方法。然而,在一些實施例中,關系操作符可以潛在地導致值類型的裝箱形式和拆箱形式之間的行為差異,使用Java作為示例如下所示:

Point p1=__MakeValue(0,1);

Point p2=__MakeValue(1,0);

Point p3=__MakeValue(1,0);

assert(!p1.equals(p2));//值判等

assert(p1?。絧2);//再次值判等

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

Object box1=p1,box2=p2,box3=p3;//將它們裝箱

assert(box1==box1);//x==x總成立(除了NaN(非數(shù)字))

assert(!box1.equals(box2));//Object.equals調(diào)用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");//不確定

利用小調(diào)整,在Java中上面所有的測試可以在整型和整數(shù)(Integer)的情況下被重現(xiàn)。然而,對于一些小的整數(shù)值,由于Integer.valueOf工廠方法的特點而非原生、值類型或箱的內(nèi)在特征,貓不會存活。

第四,盡管原生不具有對應于空引用的值,但是原生具有一般是零的默認值。該默認值在未初始化的字段和數(shù)組元素的初始內(nèi)容中出現(xiàn)。因此可以為每個值類型指定默認值。例如,一種技術是將復合值設置為在其所有子字段中是遞歸默認的。假如預定義的默認值在諸如Java之類的一些語言中是固定值,則該約定適用于許多語言背景。

在一些實施例中,即使構造函數(shù)從未創(chuàng)建默認(全零位)的值類型,值類型定義中的方法的作者也可以向默認的值類型提供行為,因為這些值類型在一些未初始化的變量中可以被觀察到。在實施例中,虛擬機104要么禁止無參數(shù)的構造函數(shù)要么要求它們產(chǎn)生默認值,以便于避免“決斗的默認值”。

在一些實施例中,作為替代,虛擬機104通過強制包括公有的空構造函數(shù)來迫使顯式地構造默認值,像這樣:public Point(){x=0;y=0;}。在公有的空構造函數(shù)中,所有子字段被初始化為默認值,否則編譯器102和/或驗證器106將報告錯誤。可替代地,虛擬機104可以不允許空構造函數(shù),并且為默認值保留其含義。

在一些實施例中,作為替代,虛擬機104允許通過對標準類定義施加的模式或語法來指定更精心制定的默認值。然而,對此存在三點考慮:(1)在一些情況中默認值將要求特殊的擴展而不是簡單的限制,(2)在一些情況中默認值將包括特殊的規(guī)則以在來自空構造函數(shù)的副作用的情況下編碼,以及(3)相比于全零位的約定,在運行時應用由用戶指定的默認值可能潛在地具有更高的成本。

3.7示例性實現(xiàn)細節(jié)

在一些情況中,類的某些特征對于用于特定實施例的值類型將沒有意義。下文以問題和回答的格式表示根據(jù)特定實施例的用于值類型的設計和/或實現(xiàn)決策。然而,下文所描述的回答不是決定性的;其他實施例可以提供對下文所呈現(xiàn)的問題的不同回答。因此,其他實施例對于每個問題可能有所不同。在一些實施例中,本節(jié)中所描述的關于值類型的限制在虛擬機104中被實現(xiàn)為供驗證器106遵循的附加規(guī)則。

子類型化(subtyping)

值類可以擴展引用類類型嗎?在大多數(shù)情況中,不可以。

引用類可以擴展值類型嗎?在大多數(shù)情況中,不可以。

具體的值類可以擴展另一值類型嗎?在大多數(shù)情況中,不可以。(因為具體的值類是最終的。)

值類型定義可以是抽象的或非最終的嗎?在大多數(shù)情況中,不可以。

值類型定義可以實現(xiàn)接口嗎?可以。當我們將值類看作接口實例時,裝箱可以發(fā)生。

值類型可以參與基于繼承的子類型化嗎?在大多數(shù)情況中,不可以。(就像原生那樣。)

是否存在用于值的根類型(諸如Java中的Object超類型)?不一定。在一些實施例中,值類型的超類型可以被實現(xiàn)為模板化機制。

包含

值類型可以包含引用類型的字段嗎?可以。

引用類可以包含值類型的字段嗎?可以。

值類型可以包含值類型的成分字段嗎?可以。

數(shù)組可以包含值類型的元素嗎?可以。(在一些語言中,數(shù)組是對象的類型)。

值類型可以包含數(shù)組類型的字段嗎?可以。(例如,當數(shù)組是對象時)。

值類型可以包含非最終字段嗎?在許多實施例中,不可以,但是其他實施例可以允許具有非最終字段的值類型。

值類型的所有字段都必須是遞歸不變的嗎?不一定。(遞歸不變性是類型的獨立特征)。

值類型可以具有成員類型嗎?可以。(非靜態(tài)成員類型具有記錄包含值的隱藏字段)。

值類型可以是成員類型嗎?可以(如果它們是非靜態(tài)的,則它們具有指向包含對象的隱藏字段。)

當創(chuàng)建值類型的數(shù)組時,初始元素是什么?它們都是默認的全零位值。(就像原生那樣。)

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

其類型是值類型的局部變量的初始值是什么?看情況,在一些實施例中指派規(guī)則禁止觀察這樣的值,直至第一次指派。

值類型可以包含其自身類型的字段嗎?在大多數(shù)情況中,直接地或間接地都不可以(類似于一些語言中的現(xiàn)有限制:類不能將其自身作為子類)。

兼容性

值類型是對象嗎?不一定,盡管值類型可以被裝箱成對象。

原生是值類型嗎?可能是。(值類型命名的整型、布爾型等將向包裝器類提供良好的繼承者,就像它們存在于諸如Java之類的當前語言中那樣。)

值類型的數(shù)組是否為協(xié)變的?在大多數(shù)情況中,不是。(就像原生那樣,值類型箱的數(shù)組是協(xié)變的)。

值類型是否參與隱式轉換?在大多數(shù)情況中,不參與。(在一些實施例中,虛擬機104不需要實現(xiàn)隱式轉換,諸如Java中的int toUnsignedInteger)。

每個值類型都定義了類似對象的方法(toString等)嗎?有時是。在一些實施例中,虛擬機104需要類似對象的方法以使得它們的裝箱形式可以與期待對象而不是值類型的現(xiàn)有API互操作。然而,不是在所有實施例中都需要類似對象的方法。

是否存在用于這些方法的默認的按成分的實現(xiàn)?是的。例如,用于箱的根類型是用來放置默認的按成分的代碼的邏輯位置。

值類型可以被序列化嗎?看情況。在一些實施例中,為了阻止違背封裝性,虛擬機104不實現(xiàn)用于值類型的序列化。然而,在其他實施例中,虛擬機104可以實現(xiàn)用于值類型的序列化。

值類型的用戶可以請求原子性嗎?可以。在一些實施例中,可以使用諸如關鍵字volatile或_AlwaysAtomic之類的關鍵字指定原子性。

當將值類型指派給泛型對象時發(fā)生了什么?虛擬機104基于值類型的類文件自動將值類型裝箱到虛擬機104生成的類中。生成的類文件反映值類型的字段和方法,但是生成的對象包含頭部信息并且因此可以被用于標識以及被用于與期待對象的API的互操作性。

當空值被分配給值類型(或者與值類型相比較)時發(fā)生了什么?如果該值類型是裝箱的,則引用比較將返回不相等;如果值類型是拆箱的,則拋出異常。

封裝性

值類型可以具有非公有的字段嗎?可以。

值類型可以具有非公有的方法嗎?可以。

值類型可以具有靜態(tài)方法或字段嗎?可以。

值類型是怎樣構造的?通過調(diào)用構造函數(shù)。值類型構造函數(shù)事實上是工廠方法,因此(使用JVM字節(jié)碼作為示例)在字節(jié)碼中不存在new;dup;init跳躍(dance)。

值類型的定義者可以要求其所有成分值的原子性嗎?可以。例如,通過在值類型定義中使用關鍵字或符號,這些關鍵字或符號指示操作將始終是原子的。

值類型的封裝性可以被布置為排除所有默認的按成分的操作嗎?可以。(例如,通過重載相關方法)。

值類型可以在不要求客戶機重新編譯的情況下改變尺寸或布局嗎?可以。

值類型的封裝性可以被布置為排除其所有字段是零的值嗎?在大多數(shù)情況中,不可以。(如上文所指出的,這是慎重的妥協(xié)。如上文所指出的,一些實施例中的默認值可以與無參數(shù)的構造函數(shù)值一致。)

諸如字節(jié)碼之類的虛擬機指令可以以訪問值類型的私有字段的方式被使用嗎?取決于實施例。

其他細節(jié)

是否存在對值類型的復雜度的限制?是的。在一些實施例中,虛擬機104對值類型的成分的數(shù)量和/或尺寸施加限制以便于做出性能保證。例如,但是不足夠低以做出性能保證。例如,值類型可以被限制為諸如255字之類的閾值。

虛擬機104支持通過拆分超類來重構值類型嗎?在大多數(shù)情況中,不支持,除非虛擬機104允許抽象的值類型。

虛擬機104支持將方法重構到值類型中或從值類型中將方法重構出來嗎?支持,例如,與默認方法的公共接口可以被用于該目的。

虛擬機104支持對于裝箱的值調(diào)用值類型的方法嗎?支持。在一些實施例中,虛擬機104自動對值進行裝箱和拆箱以創(chuàng)建用于API的橋。例如,當使用Point時,取決于上下文和環(huán)境,該表示將有時為值類型,有時為箱引用類型。

在一些實施例中,虛擬機104禁止值類型的子類化和子類型化以避免指針多態(tài)性。抽象超類型(比如Java中的接口Comparable)可以被考慮,因為它們不能被實例化。結果,虛擬機104可以因此確保所有方法以方法接收者的確切類型被明確地解析。在一些情況中,該決策還回避了值類型數(shù)組的問題,如果數(shù)組可以包含(例如)2字段Point和3字段ColoredPoint(染色點)值,則值類型數(shù)組可以包括尺寸可變的元素。對于數(shù)組,由于原生數(shù)組已經(jīng)具有完全同構的元素,因此依賴原生語義是方便的。然而,該方法不是沒有問題。例如,對于實現(xiàn)Comparable的值類型Bignum,虛擬機104可以允許箱的數(shù)組Bignum.__BoxedValue[]是接口數(shù)組Comparable[]的子類型,但是在一些實施例中扁平的數(shù)組類型Bignum[]不能也是Comparable[]的子類型。

3.8示例性字節(jié)碼和類型描述符

存在可以在虛擬機104的指令集(例如,字節(jié)碼)中顯現(xiàn)值類型的許多方式。例如,用于值類型的全新指令可以通過將值類型當作全新的結構體或者重載現(xiàn)有指令以接受值類型或引用來實現(xiàn)。本節(jié)關注可以被實現(xiàn)為生成、加載、存儲和/或以其他方式操縱值類型的新指令。然而,如上文提到的,其他實施例可以重載現(xiàn)有指令以實現(xiàn)類似的效果。

建立在上面“示例性類文件結構”中所討論的描述符示例上,存在用于原生的單字母類型描述符(例如,用于整型的I)、用于類的“L”描述符(例如,L ClassName),并且對于任何類型,可以通過追加“[”來為該類型的數(shù)組導出類型描述符。在實施例中,為值類型添加另一形式;用于值類型com.foo.Bar的類型描述符將會是Q com/foo/Bar;這就像用于引用類型的“L”描述符一樣,除了不同的符號“Q”。例如,考慮以下方法:

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

用于以上方法的簽名將會是(Q Point)D,這指示它采用值類型Point的單個參數(shù)并且返回雙精度型。

新虛擬機104指令的示例以如下格式描述:

//描述

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

在一些實施例中,對于所有操作碼,“qdesc”是用于值類型的Q描述符。然而,對于許多指令,驗證器106可以從指令的上下文推斷描述符。因此,如果這樣的描述符可以替代地通過上下文來推斷,則一些實施例可以選擇忽略來自指令的這種描述符。用于局部變量401的表槽(slot)和用于操作數(shù)棧402的表槽可以保持值類型以及原生或引用。

在一些實施例中,值類型消耗局部變量401和/或操作數(shù)棧402中的單個槽。因此,每個槽不必具有固定長度的尺寸。然而,在其他實施例中,值類型消耗多個槽,類似于在一些JVM實現(xiàn)中諸如雙精度型之類的尺寸過大的原生類型如何被設計為占用兩個槽而不是一個槽,從而使得槽可以具有相等的尺寸。在一些實施例中,虛擬機104可以在不重新編譯代碼的情況下改變槽的尺寸和布局。后面的節(jié)中討論關于虛擬機存儲器布局300內(nèi)的值類型的存儲的附加細節(jié)。

在實施例中,為了操縱棧幀400上的值類型,虛擬機104支持以下指令。同樣,盡管以下示例中的一些形式可以認為是不必要的,但是示例顧及到明確性和完整性。因此,在一些實施例中,新指令的數(shù)量可以遠小于下文所描述的新指令的數(shù)量。

//從局部變量加載值類型

vload[qdesc?,index]->value type

//將值類型存儲到局部變量中

vstore[qdesc?,index]value type->

//創(chuàng)建值類型的新數(shù)組

vnewarray[qdesc]size->arrayref

//將值類型存儲到數(shù)組中

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

//從數(shù)組加載值類型

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

//提取來自值的成分

vgetfield[field-desc]value type->result

//將成分插入到值類型中(為了構造函數(shù)的私有使用)

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

//構建具有全部默認的成分的新生值類型(為了構造函數(shù)的使用)

vnew[qdesc]->value type

//對值類型調(diào)用方法

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

//返回值類型

vreturn[qdesc?]value type

在一些實施例中,虛擬機104支持可以對任何類型的幀400內(nèi)容操作的若干“多態(tài)的”指令,諸如JVM字節(jié)碼集中的“dup”;這些指令可以被擴展為同樣支持值類型。在大多數(shù)情況中,這些多態(tài)指令可以用最少的努力被重載到現(xiàn)有指令上。使用JVM指令碼集作為示例,vinvoke功能可以被重載到invokestatic上,而vgetfield功能可以被重載到getfield上。

在一些實施例中,上文提到的字段和方法描述符將會是常量表201引用,諸如指代方法引用結構207、字段引用類型206和/或類信息結構203的引用。在一些實施例中,描述符的成分通過值類型的標稱名稱(例如,沒有任何“Q”前綴)指代值類型。對應類的裝箱形式具有例如從描述符語言(例如,L Foo)導出的它們自己的字節(jié)碼名稱。在一些實施例中,虛擬機104支持克隆常量表201類型,諸如CONSTANT_ValueMethodref,使用Java類文件作為示例。

在一些實施例中,值類型中的靜態(tài)方法重復使用為適當?shù)念悓崿F(xiàn)的相同指令,而不需要特別指向到值類型的特殊指令。例如,使用JVM字節(jié)碼集作為示例,可以使用invokestatic來調(diào)用值類型中的靜態(tài)方法。在一些實施例中,類似于靜態(tài)方法,靜態(tài)字段可以重復使用由虛擬機104實現(xiàn)的用于操縱靜態(tài)字段的相同指令來操縱適當類的靜態(tài)字段。

在一些實施例中,虛擬機104阻止構造函數(shù)調(diào)用通過引用傳遞要構造的值類型。替代地,值類型構造函數(shù)被實現(xiàn)為將作為靜態(tài)方法被調(diào)用的靜態(tài)工廠方法。用于成分初始化的各變化步驟通過特權指令vputfield的使用而被內(nèi)部地呈現(xiàn)給構造函數(shù),該特權指令vputfield與為用于初始化屬性對象的最終字段的構造函數(shù)保留的特殊指令(諸如JVM字節(jié)碼中的putfield)等效地操作。要注意vputfield返回更新后的值,因此不存在副作用發(fā)生的機會。

在一些實施例中,虛擬機104將如構造函數(shù)使用的vnew和vputfield操作符的效果結合到vpack指令中,vpack指令將會采用棧上的一系列成分。這些成分的順序和類型將由包含值類型定義隱式地定義。這將使得一些簡單的構造函數(shù)稍微更加緊湊,但是可能導致虛擬機104中實現(xiàn)的指令及其包含類之間的新型耦合。在一些實施例中,虛擬機104對作為命名字段的簇(cluster)的復合類型進行操作,而不是對入棧的值的有序元組進行操作。在一些情況中,如果每個字段初始化具有其自己的vputfield操作碼,則虛擬機104指令和源代碼之間的對應關系可以更易于追蹤。

在一些實施例中,當從較高級別的指令生成較低級別的指令時,改變某個值類型的值內(nèi)的字段的一個或多個較高級別的指令可以被識別。該值可以是例如潛在地具有多個不同的成分字段的值類型的實例。本文描述了這種值類型的示例,諸如點(Point)或復數(shù)(Complex)??梢源_定的是,在較低級別的指令的上下文中,用于該值的至少一個成分字段的數(shù)據(jù)將被集體存儲在單個容器內(nèi)。例如,字段可以被存儲為其對應的子值的拆箱表示,而不是對存儲相應子值的其他容器(多個容器)的引用。響應于該確定,生成單個較低級別的指令。這種較低級別的指令的一個示例是本文所描述的vputfield指令。

在一些實施例中,所生成的單個較低級別的指令被配置為命令解釋器108識別與字段對應的容器的一部分,諸如一個或多個位。單個較低級別的指令還被配置為命令解釋器108根據(jù)一個或多個較高級別的指令來改變該部分。識別和/或改變可以至少部分基于與值的值類型相關聯(lián)的元數(shù)據(jù)。例如,指令可以使得解釋器108使用用于值類型的字段定義來定位該部分和/或實行用于對應的值類型定義的訪問控制信息、類型檢查等等。在實施例中,單個較低級別的指令命令解釋器108在不使用指針定位字段的情況下和/或在不必發(fā)出使值開放到其成分字段中的分開指令的情況下進行該操作。

在實施例中,可選擇性地通過重新排序、合并或分開彼此相關并且與可以讀或寫存儲在容器中的值或容器的至少一些成分字段的任何其他指令相關的兩個或更多個這種較低級別的指令的效果來生成較低級別的指令。這種效果的重新排序、合并或分開可以受保護存儲在容器中的值的每個成分字段以及存儲在容器中作為整體的值的一致性的規(guī)則影響。因此,技術可以包括使用分層的數(shù)據(jù)結構的嵌套存儲器模型,當對象拆分成值時,其可以拆分成更小的值并且最終一直向下拆分成成分原生和引用。

根據(jù)實施例,一種方法包括:當解釋諸如Java字節(jié)碼之類的指令時,識別指令以將第一個較小的值作為第二個較大的值的字段插入。該指令可以是例如單個較低級別的指令,諸如上面生成的指令。第二個值可以是例如具有集體存儲在容器中的多個不同成分字段的經(jīng)定義的值類型的值。第一個值可以是例如對應于字段的子值。在實施例中,確定第二個值具有某個值類型?;谂c某個值類型相關聯(lián)的元數(shù)據(jù),對應于字段的第二個值的一部分被定位,并且第一個值被加載到該部分中。這可以包括例如基于與某個值類型相關聯(lián)的值類型定義數(shù)據(jù)來實行訪問控制信息和類型檢查,和/或使用值類型定義數(shù)據(jù)來定位相關部分。在實施例中,選擇性地通過重新排序、合并或分開兩個或更多個這種較低級別的指令的效果來生成較低級別的指令,諸如上文所描述的。

3.9裝箱和對象互操作性

在實施例中,每個值類型具有對應的箱類,就像在Java中Integer是用于整型的箱類型。在一些實施例中,虛擬機104或編譯器102從用于值類型的類文件中所提供的定義自動導出用于值類型的箱類的類文件(或者反之亦然),而不是要求值類型及其對應的箱的分開編碼。例如,方法和字段可以從值類的類文件得到,但是其中箱類文件包含標識符,該標識符指示虛擬機104應當將箱類文件解釋為指代適當?shù)膶ο箢?。箱類文件還可以包含可以不存在于值類型的類文件中的附加的元數(shù)據(jù),諸如超類(例如,Java中的Object超類)的存在??商娲兀摂M機104可以生成對于值類型和箱表示這二者通用的一個類文件,其中類文件取決于上下文而被虛擬機104不同地處理。例如,如果值類型使用描述符“Q Foo”,則用于對應的箱類的描述符可以是“L Foo”。對于這兩種類型,虛擬機104將知道尋找被稱為Foo的類文件并且基于哪個描述符被使用來生成值視圖或引用視圖。

在一些實施例中,諸如構建之類的公共操作具有用于值類型或箱類的不同機制。例如,編譯器102可以生成多個版本的類工件(class artifact)(例如,具有簽名(...)V的標準構造函數(shù)和具有簽名(...)Q Foo的值構造函數(shù))或者虛擬機104將根據(jù)需要從其中一個的指令導出另一個。在一些實施例中,對于值類型Foo,F(xiàn)oo可以被寫為指代值形式,而Foo.__BoxedValue被寫為指代Foo的裝箱形式。

在實施例中,值類型的裝箱表示和拆箱表示之間的轉換像諸如Java之類的一些語言中當前的原生箱(例如,valueOf(boxed))那樣通過遵循命名約定的方法來表示,或者可以由像下面的轉換指令來表示:

//將值裝箱

v2a[qdesc]value->ref

//將值拆箱

a2v[qdesc]ref->value

值之間的比較(類似于JVM字節(jié)碼集中的acmp和icmp字節(jié)碼)也可以由遵循命名轉換的方法來表示,或者用像下面的特殊指令來表示:

//使用按成分的、按位的以及引用判等來比較兩個值

vcmp[qdesc?]value,value->boolean

在一些實施例中,盡管在一些情況中像操縱原生和引用的指令那樣處理新的值類型指令的“克隆”是有用的,但是在實施例中轉換和比較指令可以使用方法調(diào)用(例如,vinvoke)來實現(xiàn)。

在一些實施例中,像數(shù)組那樣,箱類由虛擬機104生成。在實施例中,系統(tǒng)將箱代碼盡量多地分解為常見的抽象超類。在Java中,這大約是為經(jīng)典對象采取的方法,其中默認行為在java.lang.Object中找到。

3.10示例性代碼

示例:構造

在本節(jié)中使用上面在“新字節(jié)碼和類型描述符”中介紹的新指令與來自JVM字節(jié)碼集的指令的組合來描述創(chuàng)建和使用值類型的示例。盡管JVM字節(jié)碼被用于提供示例,但是由示例描述的技術不限制于Java、JVM或任何特定語言或虛擬機架構。

在一些實施例中,通過首先執(zhí)行創(chuàng)建未初始化的對象的指令并且然后調(diào)用構造函數(shù)來初始化對象。用于值類型的構造函數(shù)的行為與工廠方法更類似。下面示出了為Point的構造函數(shù)生成的示例性指令。

為了在棧幀400的局部變量401中創(chuàng)建Point的實例,工廠方法被調(diào)用,并且結果被存儲在本地:

在上面的示例中,為了簡化闡述,值類型的構造函數(shù)的名稱被更改為<new>,以強調(diào)該構造函數(shù)是工廠方法。

示例:嵌套值

在上面的示例中,當讀取嵌套值時,首先讀取它的封閉值。

示例:數(shù)組

在實施例中,利用vnewarray指令來創(chuàng)建數(shù)組,并且非常像任何其他數(shù)組類型那樣操縱數(shù)組。以下是示例:

示例:方法調(diào)用

在實施例中,靜態(tài)地解析對于值類型的方法。invokestatic指令對于調(diào)用值類型的靜態(tài)方法和非靜態(tài)方法這二者(作為指令/字節(jié)碼語法)將會是足夠的,但是為了清楚地闡述,一些實施例對于值類型的非靜態(tài)方法使用新的調(diào)用指令vinvoke。以下是示例:

示例:裝箱

在一些實施例中,當值類型被指派了類型Object、它的箱類型或它實現(xiàn)的接口類型的變量時,變量的內(nèi)容由編譯器102和/或虛擬機104自動裝箱。例如:

示例:拆箱

在實施例中,當值類型從類型Object、它的箱類型或它實現(xiàn)的接口類型的變量被分配時,首先檢查引用以查看它是否是對應的箱類型,并且(如果是的話)然后值被拆箱。以下是示例:

在一些實施例中,裝箱引用具有對它直接調(diào)用的值類型的方法,例如:

示例:扁平化的散列表

在一些實施例中,因為值類型沒有指針,所以值類型可以被用于通過移除間接尋址的級別來使一些數(shù)據(jù)結構扁平化。扁平化不僅移除了來自關鍵路徑的依賴性負載,而且(典型地)將相關數(shù)據(jù)移動到相同的高速緩存線上。

在一些情況中,調(diào)優(yōu)良好的、尺寸可變的散列表可以在不超過兩個高速緩存線引用中答復查詢,其中一個引用用來針對表尺寸咨詢表頭部,一個引用用來探查表中的條目。如果表條目在承載表的數(shù)據(jù)數(shù)組內(nèi)是扁平化的,則這可以實現(xiàn),并且在值類型的幫助下這成為可能。

上面的代碼實際上觸摸了三個高速緩存線,以便于從數(shù)組頭部提取數(shù)組長度。在一些實施例中,解決該問題包括將數(shù)組長度向上提升到散列表頭部中。

上面的代碼避開將具有默認值的條目(零散列、空字符串引用)與尋找條目失敗區(qū)分開的問題。這是使面向指針的算法(例如,在Java中)適應于值類型的典型問題。這可以由不同的實施例以若干方式解決。一種方式是引入表達可選擇的條目(條目加上布爾型)的值,并且從getEntry返回該值。要注意在用于getEntry的慢路徑的末端處,實現(xiàn)默認(空)條目值的能力在此可以是有用的。出于上面給出的原因,默認值是一些語言景觀(諸如Java)的部分。

在上面的示例中,__AlwaysAtomic關鍵字的效果是確保數(shù)組元素值在沒有內(nèi)部競爭的情況下被一致地讀取。在沒有該修改的情況下,在一些平臺上,結構撕裂可能導致值可能與錯誤的鍵相關聯(lián)的狀態(tài)。該危害來自扁平化;它在數(shù)據(jù)結構的“指針豐富的”版本中不會呈現(xiàn)。

在一些實施例中,計算平臺能夠借助于64位存儲器引用來在沒有額外成本的情況下實現(xiàn)用于該數(shù)據(jù)結構的原子性。這假設值成分可以被打包為32位,這是通常的情況。在一些情況中,甚至四個成分的值可以容納在128位中,并且大多數(shù)硬件平臺以合理的成本提供原子的128位讀和寫。對于較大的值,比如具有五個或更多個成分的值,用于原子性的成本將急劇增加,這是原子性不是默認的原因。

要注意為了對于整型和字符串型起作用,該示例性數(shù)據(jù)結構是“硬連線的”。對應的泛型類將從扁平化的數(shù)組獲得一些益處,但是可以不直接對拆箱的整型起作用。在一些實施例中,虛擬機104實現(xiàn)類似模板的機制來對非引用進行參數(shù)化以解決該問題。

示例:比較

如上文所指出的,在一些實施例中值類型可以實現(xiàn)接口。這是支持比較的值類型的示例:

自動創(chuàng)建的箱類適當?shù)貙崿F(xiàn)接口,橋接到所給出的compareTo方法。vinvoke指令還可以直接調(diào)用如所編寫的compareTo方法。

這是對接口函數(shù)的調(diào)用的一些示例。

像類那樣,通常存在對實現(xiàn)接口的方法做出直接的、無接口的調(diào)用(在該情況中vinvoke)的選項。

在上面的示例中,接口(諸如根據(jù)Java的當前規(guī)則)采用擦除的Object參量。在值類型的背景下,允許類型參量(Comparable<T>中的T)綁定到值類型Bignum并且因此將箱方法一直橋接到方法compareTo。

在一些實施例中,每個值類型實現(xiàn)自組織(ad hoc)接口或抽象超類型,諸如下面的示例:

3.11附加的示例性選項

子類型化。在一些實施例中,虛擬機104創(chuàng)建用于值類型的新的根類型以支持用于解析的抽象值超類型。

擦除vs.具體化。在實施例中,箱僅對箱操作,而值類型僅對值類型操作。某些橋方法由虛擬機104(靜態(tài)地或者動態(tài)地)自動生成。

按成分方法。在一些實施例中,按成分方法是默認的。例如,過度健談的toString方法可能徹底違背秘密值成分的封裝性。用于生成用于打印、比較、散列碼等的按成分方法的機制和策略可以為了選擇性加入(opt-in)vs.選擇性退出(opt-out)的正確混合而被平衡。

增強的變量操作。在一些實施例中,比較和交換(CAS)和類似的操作作為直接暴露CAS操作的單獨特征的部分而被解決。在一些實施例中,在許多情況下值類型與引用和原生一起合并到CAS和類似的操作中。

值/原生收斂(convergence)。在實施例中,原生被集成到值類型中(例如,__ByValue class int{...}),并且成為預定義的值類型。

按字段的副作用。在一些實施例中,為了簡化,值字段是被定為最終的。然而,在其他實施例中,值字段可以不一定總是最終的。在一些實施例中,可以對值中的僅一個字段產(chǎn)生副作用,從而實現(xiàn)“通過值”的所有效率以及“通過引用”的所有可變性。

值上泛型。在一些實施例中,虛擬機104支持用于值類型的泛型(例如,List<Point>)。

數(shù)組值。聚合的空間形成2×2的矩陣{標識,無標識}×{同構,異構}。對象和數(shù)組填充“標識”行;值類型填充(無標識,異構)箱;剩余的箱可以被描述為數(shù)組值。在一些實施例中,虛擬機104提供對于數(shù)組值的支持。

3.12從類型到值類型的遷移

在諸如Java之類的一些操作環(huán)境中,如果設施在許多之前實現(xiàn)的類型寫入時已經(jīng)是可用的(例如,Java中的LocalDateTime、Integer等),假設在已經(jīng)是值類型的時間處這些類型已經(jīng)是可用的,則許多之前實現(xiàn)的類型可能應當已經(jīng)是值類型。在一些實施例中,虛擬機104支持將以上提到的類型實現(xiàn)為值類型的能力同時維持API互操作性。

遷移兼容性具有兩個重要的方面:二進制兼容性(當現(xiàn)有的二進制指代預先遷移的類型時,二進制兼容性發(fā)生)以及源兼容性(當針對遷移的類型重新編譯文件時,源兼容性發(fā)生)。源兼容性一般要求當引用類型被遷移為值類型時,對該引用類型的每個操作具有兼容的含義;這不僅包括像構造和方法調(diào)用那樣的值安全的慣用語法,而且包括諸如鎖定之類的值不安全的操作,因為現(xiàn)有代碼可能執(zhí)行依賴標識的操作。

假如預先存在的類型“WasARef”被遷移為值類型,并且由遷移注釋為:

__Migrated__ByValue class WasARef{...}

以下事實幫助兼容性,即如果類“X”從引用類型遷移為值類型,則類型描述符“L X;”在遷移后仍然是合法的類型,它指代現(xiàn)在的值類型的裝箱形式。如上文所討論的,用于值類型的裝箱版本的類文件可以從值類型的類文件生成?;蛘哌@二者可以共享公共的類文件。因此,只要維持了命名約定,那么導致類型不安全的操作或使用的對值類型的先前使用可以替代地利用值類型的裝箱版本。因此,為了提供用于遷移的類型的源兼容性,在一些實施例中虛擬機104通過提供從“L”橋接到“Q”形式的橋方法來至少為遷移的所有值類解決值不安全的操作,以使得重新編譯的API繼續(xù)與舊客戶機工作。

3.13更新字段的值

在實施例中,虛擬機104被配置為針對當更新一個字段和一些其他字段是易變的時可能出現(xiàn)的問題而使用指令的替代設計:

例如,如果代碼顯示為:

kludge k;

k.baz=7;

那么按照語句與以下語句同義的理論

k=kludge(k.flag,7);

可以寫入“flag”字段。在實施例中,虛擬機104提供對于具有可以獨立寫入的兩個易變字段的“像值一樣的”結構的支持。然而,為了彌補,源語言可以在語言級別實現(xiàn)更精心制定的語義。例如,源語言可以遵循諸如“當且僅當值類型是變量的值時,值類型的字段是變量”之類的規(guī)則。因此,如果以下語句是合法的,

c.im=7;

則以下語句是不合法的:

myComplexHashMap.get(key).im=7;

只要在更新變量的字段時保持變量中的復數(shù)值,那么編碼員可以在使用用于復數(shù)的值類和非值類之間高效地來回移動。

同時,能夠獨立寫入值的兩個(可能易變的)字段中的每個字段的虛擬機104指令可以被提供。因此,在一些實施例中,以下技術:不向上面介紹的那些添加新的虛擬機104指令,卻將作為vstore或vastore指令的部分的“desc”從

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”的類型復數(shù)的字段的值類型“foo”的變量,則編譯

p.phase.im*=trouble();

的示例性方式是

vload"Qfoo;.phase.im"4

invokewhatever"trouble"

mul

vstore"Qfoo;.phase.im"4

該方法在某些方面比vputfield/dup_X1跳躍更高效。用于將看上去像是鏈式字段訪問的東西打包成單個描述符的正當理由是它畢竟只是個描述符;它解析為單個偏移并且在一些實施例中使用它的vload或vstore僅執(zhí)行對存儲器的一次讀或寫操作。

在一些實施例中,類型檢查彌補了上面所描述的技術。例如,對于vload"Qfoo;.phase.im"4,局部變量槽4中的數(shù)量的類型必須是Qfoo;,但是加載到棧上的元素具有與子字段的類型.phase.im相等的類型,它可以是雙精度型或整型,這取決于復數(shù)的實現(xiàn)。

4.0修改后的加載進程

在一些實施例中,虛擬機104修改上文在“加載、鏈接和初始化”中所描述的加載進程來彌補值類型的引入。本節(jié)描述所述技術可以被修改的若干示例性方式。然而,示例僅適用于特定實施例并且不是決定性的。

如上文所描述的,當類文件200被加載到虛擬機存儲器布局300中時,存儲器被分配給所加載的類的靜態(tài)字段。在類的靜態(tài)字段具有值類型的情況下,然后在一些實施例中,需要被分配的空間量位于用于值類型的類文件中而不是在用于當前類的類文件中。結果,虛擬機104基于為被加載的類的類文件中的字段指定的符號引用來定位值類的類文件,并且計算所需要的存儲器的量。不過,如果用于值類的類文件已經(jīng)被加載,則虛擬機104可以執(zhí)行計算并且在與指示總尺寸的值類相關聯(lián)的元數(shù)據(jù)中高速緩存結果。該元數(shù)據(jù)然后可以被虛擬機104讀取,而不是多次執(zhí)行計算。例如,需要由虛擬機104為該字段在共享區(qū)域301中分配的空間量將是值類型的成分的和。這具有如下警告,即如果值類型具有值類型的字段(假設實施例允許這樣的字段),則所需要的存儲器的計算被遞歸地執(zhí)行,對總數(shù)進行合計。

類似地,如果所加載的類的實例在堆302上被創(chuàng)建,則用于保持值類型的實例字段的所需要的空間量可以以相同的方式計算??商娲?,該計算可以提前執(zhí)行并且高速緩存為與值類型和/或對象類相關聯(lián)的元數(shù)據(jù),以防止虛擬機104必須在每次實例化對象類時執(zhí)行計算。

5.0存儲考慮

如上文所討論的,值類型打算使用扁平化表示來存儲并且通過值傳遞。因此,當在保持值類型的堆302上創(chuàng)建對象時,值類型的內(nèi)容被存儲在對象內(nèi),而不是被分配在堆302上的單獨區(qū)域中的對值類型的引用。此外,當值類型被加載到棧幀400中時,是值類型的內(nèi)容被復制到局部變量401和/或操作數(shù)棧402中,而不是引用。

在一些實施例中,局部變量401表示保持一個或多個“容器”的數(shù)據(jù)結構,諸如保持若干槽以存儲用于局部變量401的各個值的數(shù)組。分配用于局部變量401的空間的一種技術是分配具有固定尺寸的容器。例如,虛擬機104可以分配數(shù)組,在該數(shù)組中每個槽被設定尺寸以適配原生或引用。因此,原生通過值被存儲在槽中,而非原生被分配在堆302上并且在槽中存儲對堆302的引用。在一些情況中,表示多個其他原生的原生(諸如雙精度型)被看作占用多個槽。然而,值類型由用戶定義并且因此可以具有可能不整齊地適配固定尺寸的容器的可變尺寸。

在一些實施例中,諸如當JIT編譯器109接管并且編譯正被執(zhí)行的一個或多個方法的虛擬機104指令時,執(zhí)行代碼的全局分析。結果,虛擬機104可以確定執(zhí)行特定的經(jīng)編譯的方法將需要的容器尺寸。然而,當使用解釋器108時,虛擬機104在沒有全局分析的益處的情況下一次一個指令地執(zhí)行程序。因此,當棧幀400(例如,作為方法調(diào)用的結果)被創(chuàng)建時所分配的用于局部變量401的容器可能被設定了不足以處理特定值類型的尺寸。例如,假設局部變量401包括兩個容器,各自分配了64位的存儲器。如果給定方法的虛擬機104指令指定將諸如整型之類的較小的值存儲到第一容器中,則存儲器分配可能是低效的(分配多于需要的空間),但是整型可以被存儲在容器中。然而,如果虛擬機104指令指定在容器中存儲128位值類型,則容器對于容納值類型而言將不夠大。作為響應,虛擬機104會將容器重新分配為128位以便于存儲值類型。因此,存在與過大地設定被用于存儲局部變量401的容器的尺寸相關聯(lián)的存儲開銷以及與過小地設定容器的尺寸并且執(zhí)行頻繁的重新分配相關聯(lián)的處理開銷。

在一些實施例中,操作數(shù)棧402還被實現(xiàn)為存儲一個或多個容器的數(shù)據(jù)結構。例如,操作數(shù)棧402可以被實現(xiàn)為存儲以先進先出(FIFO)順序訪問的一個或多個容器的?;蚍侄蔚臈!R虼?,在一些實施例中,將值類型存儲到操作數(shù)棧中可以導致上面關于局部變量401所討論的相同問題。

在一些實施例中,虛擬機104實現(xiàn)分配規(guī)則和存儲優(yōu)化,該分配規(guī)則和存儲優(yōu)化降低了與在容器中存儲尺寸可變的值(諸如值類型)相關聯(lián)的開銷。

5.1存儲過程流

圖5示出了根據(jù)實施例的用于在容器中存儲值類型的過程。如上文所討論的,局部變量401和操作數(shù)棧402這二者都可以被實現(xiàn)為存儲容器的數(shù)據(jù)結構。然而,圖5中示出的過程流對于被用于存儲容器的數(shù)據(jù)結構是通用的。此外,圖5中框執(zhí)行的順序不是關鍵的。在其他實施例中,與圖5的圖示相比,框可以被重新排列、合并或者劃分為分開的框。下面的解釋假設圖5的過程流由虛擬機104的解釋器108執(zhí)行。另外,下面的解釋假設在圖5的過程期間幀400是當前棧幀。

在框500處,解釋器108初始化一個或多個容器。在一些實施例中,當響應于方法調(diào)用而創(chuàng)建新的棧幀400時執(zhí)行框500。例如,該一個或多個容器可以表示用于存儲局部變量401的數(shù)據(jù)結構和/或用于存儲操作數(shù)棧402的數(shù)據(jù)結構。

在實施例中,解釋器108將所述一個或多個容器初始化為具有相同的固定尺寸。例如,解釋器108可以將容器初始化為存儲基本原生和/或引用所需要的尺寸。作為另一示例,解釋器108可以創(chuàng)建具有大于基本原生和/或引用的尺寸的固定尺寸的容器。

在一些實施例中,解釋器108將所述一個或多個容器初始化為可變的尺寸。例如,在一些實施例中,當方法被調(diào)用時,新的棧幀400被創(chuàng)建,前一個幀的操作數(shù)棧上的參數(shù)出棧并且被放置在新棧幀400的局部變量401中。因此,至少對于被用于存儲參數(shù)的容器而言,解釋器109可以將這些容器初始化為適合于方法調(diào)用所期待的參數(shù)類型(諸如原生類型、引用類型或值類型)的尺寸。例如,解釋器108可以通過檢查方法調(diào)用的描述符來確定參數(shù)類型。

然而,在一些實施例中,棧幀在存儲器中重疊以提升存儲效率。例如,調(diào)用者的棧幀可以與被調(diào)用者的棧幀在存儲器中重疊,使得調(diào)用者的操作數(shù)棧是與新棧幀的一個或多個局部變量相同的存儲器位置。在這樣的實施例中,當調(diào)用者將這些值推到前一幀的操作數(shù)棧上時,表示參數(shù)的局部變量401的容器被初始化。

在一些實施例中,解釋器108可能仍然需要用于在方法的主體內(nèi)聲明的變量(例如,無參數(shù)的局部變量)的容器。在一些實施例中,解釋器108預先分配若干容器以保持這種變量的值。然而,在其他實施例中,解釋器108延遲初始分配直至接收到將值存儲到局部變量中的指令。一旦接收到指令,則解釋器108分配對于存儲該值來說足夠大的容器。例如,容器可以通過編號(1、2、3、4等)索引,如果接收到在尚未被分配的容器的索引號處存儲值的指令,則解釋器108分配對于保持該值來說足夠大的容器。在一些實施例中,解釋器108修改用于保持容器的數(shù)據(jù)結構的元數(shù)據(jù)和/或頭部信息以將索引號映射到容器。

在框501處,解釋器108接收在所分配的容器中存儲值類型的指令。在實施例中,作為逐句通過被調(diào)用的方法的代碼的結果,解釋器108接收指令。在框501處可以被解釋器108接收的指令示例包括vstore、vastore、vload、vaload和上文描述的用于值類型的其他指令。在一些實施例中,在框501處接收的指令表示“較高級別的”指令(諸如JVM字節(jié)碼),解釋器108的任務是將該“較高級別的”指令翻譯成一個或多個“較低級別的”指令,諸如被調(diào)整為適應執(zhí)行虛擬機104的計算機系統(tǒng)的處理器的機器碼。

在框502處,解釋器108向驗證器106饋送指令以針對一批規(guī)則進行檢查。在一些實施例中,規(guī)則被設計為創(chuàng)建關于解釋器108的復制和/或重新分配努力的界限。在一些實施例中,當驗證器106檢測到規(guī)則被違背時,驗證器拋出異常,該異常由特殊的異常代碼來處理。

在實施例中,驗證器106約束容器以在被分配為用于一個種類的值類型后僅保持該值類型。因此,如果容器被分配為保持特定尺寸的值類型,則驗證器106阻止容器被用于可能具有不同尺寸要求的任何其他種類的值類型。結果,驗證器106阻止解釋器108付出努力重新分配用于多個值類型的容器。然而,在一些實施例中,解釋器108允許容器被重新指派為其他值類型,假設該值類型有相同的尺寸(或者在一些實施例中,有較小的尺寸)。在一些實施例中,前面提到的約束被維持直至容器的類型被“重置”或者指派的值被移動到其他地方。例如,“重置”指令可以重置類型和內(nèi)容,而“移動”指令將重置類型以及將內(nèi)容重新指派到另一容器(諸如在操作數(shù)棧402的頂部上)。然而,對于不實現(xiàn)這種指令的實施例,一旦被設置,則對于方法調(diào)用的剩余部分,類型可以被永久指派到容器。

在框503處,解釋器108確定值類型是否適配所分配的容器。在實施例中,如果值類型具有與所分配的容器相同或者比分配的容器更小的尺寸,則解釋器108前進到框504。否則,如果值類型比分配的容器的尺寸更大,則解釋器前進到框505。

在框504處,解釋器108將值類型的內(nèi)容存儲到容器中。

在框505處,解釋器108確定值類型要通過引用還是通過值來存儲。在一些實施例中,解釋器108考慮各種因素來確定值類型要通過引用還是通過值來存儲在容器中。例如,因素可以包括容器的性質(zhì)、值類型的成分、較低級別的指令如何利用值類型、另一容器是否已經(jīng)存儲值類型等等。在一些實施例中,如果值類型大于閾值尺寸并且被確定為不可變,則解釋器108選擇通過引用來存儲值類型。因此,對于大的值類型,解釋器108可以選擇存儲對值類型的引用而不是復制值類型的內(nèi)容。結果,通過阻止重復復制尺寸過大的值類型可以實現(xiàn)存儲和處理高效率。然而,由于值類型被保證是不可變的,因此從用戶的視角來看,不存在副作用的風險;原生值與值類型的處置之間不存在區(qū)別。如果解釋器108確定要通過值存儲值類型,則解釋器108前進到框506。否則,如果解釋器108確定要通過引用存儲值類型,則解釋器108前進到框507。

在框506處,解釋器108調(diào)整容器的尺寸。在一些實施例中,解釋器108通過對容器解除分配并且然后將容器重新分配為足以存儲值類型的尺寸來調(diào)整容器的尺寸。然而,在其他實施例中,取決于被用于存儲容器的數(shù)據(jù)結構,解釋器108可以被配置為在不執(zhí)行解除分配的情況下分配更多的存儲器以增加容器的尺寸。

在框507處,解釋器108在堆302上為值類型分配空間。在實施例中,解釋器108查找值類型的尺寸并且在堆302上分配對于存儲值類型來說足夠大的空間。然后解釋器108在分配的空間處在堆302上存儲值類型。

在框508處,解釋器108在容器中存儲對值類型的引用。在實施例中,在框507處解釋器108存儲對在堆302上為值類型分配的空間的引用。

在一些實施例中,在框505處的確定中,因素是另一容器是否已經(jīng)存儲用于值類型的值的拷貝。在這種情況中,如果解釋器108確定將值類型存儲為引用,而不是在堆302上存儲值類型并且在容器中存儲對堆302的引用,則解釋器108在容器中存儲對存儲值類型的其他容器的引用。例如,并非將來自局部變量的值類型復制到操作數(shù)棧402,解釋器108可以替代地復制對存儲用于該局部變量的值類型的容器的引用。作為另一示例,并非將來自局部變量的值復制到另一局部變量,解釋器108可以替代地復制對存儲第二個局部變量的值的容器的引用。在一些實施例中,僅當容器中的值不可變時才執(zhí)行前面提到的優(yōu)化,以防止副作用。

6.0原子操作

在一些實施例中,虛擬機104被配置為允許值類型或值類型的選定字段被原子地訪問。因此,向虛擬機104中的每個運行的線程提供值類型(或選定字段)的一致視圖。例如,值類型可以是具有由用戶定義的多個成分的復合。取決于虛擬機104運行在其上的硬件,處理器的指令集可能不具有支持一次更新整個值類型的指令。作為示例,當構造函數(shù)為一個線程構造值類型時,另一個線程可能看到該值類型的不一致的視圖,其中僅僅值類型的一部分已經(jīng)更新。許多類型的硬件提供了用于執(zhí)行原子操作的機制,但是這些機制具有不同程度的開銷。此外,在一些情況中,硬件機制可能是不夠的;這使得經(jīng)常發(fā)生的由軟件實現(xiàn)的鎖定方案具有非常高的開銷。因此,在一些實施例中,語言允許值類型被加標志以用于在諸如整個值類型、值類型中的選定字段或者訪問值類型的獨個指令之類的不同粒度級別的原子訪問。

在一些實施例中,僅當值類型被存儲在堆302上時遇到競爭狀況和原子性的問題。這是因為在一些實施例中堆302存儲在線程之間共享的數(shù)據(jù),但是線程區(qū)域307(包括虛擬機棧)存儲僅能被獨個線程訪問的數(shù)據(jù)。因此,(通過值)存儲在棧幀400中的值類型不經(jīng)歷競爭狀況,因為僅一個線程將訪問這些值類型。然而,當值類型例如作為封裝對象的字段被存儲在堆302上時,多個線程可以潛在地讀取該值,從而導致競爭狀況。

圖6示出了根據(jù)實施例的用于訪問值類型的過程流。為了示出清楚的示例,將從虛擬機104的解釋器108的視角來說明圖6的過程流。

在框600處,解釋器108接收訪問存儲在容器中的值類型的字段的指令。在一些實施例中,解釋器108接收從值類型的字段加載值或將值存儲到值類型的字段的指令。例如,上文描述的vgetfield和vputfield指令是在框600處可以接收的指令的示例。

在框601處,解釋器108確定字段是否要被原子地對待。如果是,則解釋器108前進到框602。否則,解釋器108前進到框602。在實施例中,響應于檢測到以下情況中之一,解釋器108確定字段是原子的:值類型已經(jīng)被標記為始終是原子的,值類型的字段已經(jīng)被單獨地標記為用于原子訪問,或者指令被標記為是原子指令。例如,在源代碼文件101中,值類型的聲明、值類型的字段或使用值類型的指令包括諸如“atomic(原子的)”或“always atomic(始終是原子的)”之類的關鍵字。當編譯器102編譯源代碼文件101時,利用指示這些成分要被原子地對待的標志或元數(shù)據(jù)來標記類文件103。然后解釋器108可以讀取這些類文件103(或者加載到虛擬機存儲器布局300中的類文件103的表示)以確定字段是否要被原子地對待。

在框602處,解釋器108在沒有原子限制的情況下執(zhí)行訪問。例如,解釋器108可以通過將訪問轉換為不提供任何原子保證的較低級別的指令而在沒有原子限制的情況下執(zhí)行訪問。

在框603處,解釋器108確定字段是否是不可變的。在一些實施例中,字段或值類型作為整體與源代碼文件101中指示字段或值類型被凍結并且不能改變的關鍵字相關聯(lián)。類似于上文描述的“atomic”關鍵字,這可以作為標志或元數(shù)據(jù)被反映在類文件103和/或虛擬機存儲器布局300中以供解釋器108在框603期間讀取。如果字段是不可變的,則解釋器108前進到框602。如果字段是可變的,則解釋器108前進到框604。

在框604處,解釋器108確定字段是否被頻繁訪問。在一些實施例中,解釋器108跟蹤在每次訪問期間遞增的與值類型的字段或值類型本身相關聯(lián)的元數(shù)據(jù)。如果元數(shù)據(jù)指示訪問的數(shù)量超過了特定閾值,則解釋器108確定該字段被頻繁訪問。然而,在其他實施例中,還考慮時間分量,諸如追蹤在時間的某個表示(真實時間、計算機時間、所執(zhí)行的指令的數(shù)量等等)內(nèi)訪問的數(shù)量。如果解釋器108確定字段被頻繁訪問,則解釋器108前進到框605。如果解釋器108確定字段不被頻繁訪問,則解釋器108前進到框606。

在框605處,解釋器108在分開的容器中存儲字段。在一些實施例中,解釋器108將字段從扁平化的形式改變?yōu)橐帽硎?。與扁平化的值相比,對于原子地訪問來說引用通常更快。例如,對于放置/存儲指令,字段的新值可以在堆302上創(chuàng)建并且可以通過更新對新存儲器位置的引用來原子地更新字段。此外,對于原子的加載,只要字段經(jīng)由指針更新,則被加載的值要么表示整個新值要么表示整個舊值,而不可能保留部分更新的值。因此,可以避免諸如鎖定之類的需要顯著開銷的原子技術。

在框606處,解釋器108原子地執(zhí)行訪問。在實施例中,解釋器108在框606處從多個技術中選擇對于當前環(huán)境而言最高效的特定技術。例如,執(zhí)行虛擬機104的硬件可以支持可被用于原子地執(zhí)行訪問的事務或者其他基于硬件的原子指令。然而,在一些情況中,硬件可能不支持足以執(zhí)行訪問的原子指令,因此在這種情況下解釋器108回退到基于軟件的原子技術,諸如執(zhí)行鎖定。在實施例中,只要可能,相比于基于軟件的技術,解釋器108優(yōu)選基于硬件的原子指令。然而,在其他實施例中,解釋器108能夠訪問指示技術的排名的元數(shù)據(jù)。例如,當程序運行時,解釋器108可以嘗試各種類型的原子訪問技術并且基于速度將這些技術排名。

7.0硬件概述

根據(jù)一個實施例,本文描述的技術由一個或多個專用計算設備實現(xiàn)。專用計算設備可以被硬連線以執(zhí)行所述技術,或者可以包括被永久編程為執(zhí)行所述技術的諸如一個或多個專用集成電路(ASIC)或現(xiàn)場可編程門陣列(FPGA)之類的數(shù)字電子設備,或者可以包括被編程為根據(jù)固件、存儲器、其他存儲設備或者組合中的程序指令來執(zhí)行所述技術的一個或多個通用硬件處理器。這種專用計算設備還可以將定制的硬連線邏輯、ASIC或FPGA與定制的編程相組合以實現(xiàn)所述技術。專用計算設備可以是含有用于實現(xiàn)所述技術的硬連線邏輯和/或程序邏輯的桌上型計算機系統(tǒng)、便攜式計算機系統(tǒng)、手持設備、聯(lián)網(wǎng)絡設備或任何其他設備。

例如,圖7是示出在其上可以實現(xiàn)本發(fā)明的實施例的計算機系統(tǒng)700的框圖。計算機系統(tǒng)700包括用于傳送信息的總線702或其他通信機構,以及用于處理信息的、與總線702耦接的硬件處理器704。硬件處理器704可以是例如通用微處理器。

計算機系統(tǒng)700還包括用于存儲信息和要由處理器704執(zhí)行的指令的、耦接到總線702的主存儲器706(諸如隨機存取存儲器(RAM))或其他動態(tài)存儲設備。主存儲器706還可以被用于在要由處理器704執(zhí)行的指令的執(zhí)行期間存儲臨時變量或其他中間信息。這種指令當被存儲在處理器704可訪問的非暫態(tài)存儲介質(zhì)中時,使計算機系統(tǒng)700成為被定制為執(zhí)行指令中指定的操作的專用機器。

計算機系統(tǒng)700還包括存儲用于處理器704的靜態(tài)信息和指令的、耦接到總線702的只讀存儲器(ROM)708或其他靜態(tài)存儲設備。諸如磁盤、光盤或固態(tài)驅動器之類的存儲設備710被提供并且被耦接到總線702以用于存儲信息和指令。

計算機系統(tǒng)700可以經(jīng)由總線702耦接到諸如發(fā)光二極管(LED)顯示器之類的顯示器712以用于向計算機用戶顯示信息。包括字母數(shù)字鍵和其他鍵的輸入設備714被耦接到總線702以用于向處理器704傳送信息和命令選擇。另一種類型的用戶輸入設備是用于向處理器704傳送方向信息和命令選擇以及用于控制顯示器712上的光標移動的光標控制器716,諸如鼠標、跟蹤球或光標方向鍵。該輸入設備典型地具有允許設備在平面上指定位置的在第一軸(例如,x)和第二軸(例如,y)這兩個軸上的兩個自由度。

計算機系統(tǒng)700可以通過使用與計算機系統(tǒng)結合使得計算機系統(tǒng)700成為專用機器或者將計算機系統(tǒng)700編程為專用機器的定制的硬連線邏輯、一個或多個ASIC或FPGA、固件和/或程序邏輯來實現(xiàn)本文描述的技術。根據(jù)一個實施例,本文的技術由計算機系統(tǒng)700響應于處理器704執(zhí)行包含在主存儲器706中的一個或多個指令的一個或多個序列來執(zhí)行。這種指令可以從諸如存儲設備710之類的另一個存儲介質(zhì)讀取到主存儲器706中。包含在主存儲器706中的指令序列的執(zhí)行使得處理器704執(zhí)行本文所描述的過程步驟。在可替代的實施例中,硬連線電路可以代替軟件指令使用或與軟件指令結合使用。

如在此所使用的術語“存儲介質(zhì)”是指存儲使得機器以特定方式操作的數(shù)據(jù)和/或指令的任何非暫態(tài)介質(zhì)。這種存儲介質(zhì)可以包括非易失性介質(zhì)和/或易失性介質(zhì)。非易失性介質(zhì)例如包括光盤、磁盤或固態(tài)驅動器,諸如存儲設備710。易失性介質(zhì)包括動態(tài)存儲器,諸如主存儲器706。常見形式的存儲介質(zhì)例如包括軟盤、柔性盤、硬盤、固態(tài)驅動器、磁帶或任何其他磁數(shù)據(jù)存儲介質(zhì)、CD-ROM、任何其他光學數(shù)據(jù)存儲介質(zhì)、具有孔圖案的任何物理介質(zhì)、RAM、PROM和EPROM、FLASH-EPROM、NVRAM、任何其他存儲器芯片或盒。

存儲介質(zhì)不同于傳輸介質(zhì),但是可以與傳輸介質(zhì)結合使用。傳輸介質(zhì)參與在存儲介質(zhì)之間傳送信息。例如,傳輸介質(zhì)包括同軸線纜、銅線和光纖,包括包含總線402的線。傳輸介質(zhì)還可以采取聲波或光波的形式,諸如在無線電波和紅外數(shù)據(jù)通信期間生成的聲波或光波。

各種形式的介質(zhì)可以涉及將一個或多個指令的一個或多個序列承載到處理器704以供執(zhí)行。例如,指令可以初始地被承載在遠程計算機的磁盤或固態(tài)驅動器上。遠程計算機可以將指令加載到它的動態(tài)存儲器中并且使用調(diào)制解調(diào)器通過電話線發(fā)送指令。計算機系統(tǒng)700的本地調(diào)制解調(diào)器可以接收電話線上的數(shù)據(jù)并且使用紅外傳輸器將數(shù)據(jù)轉換成紅外信號。紅外檢測器可以接收紅外信號中承載的數(shù)據(jù),并且合適的電路可以將數(shù)據(jù)放置在總線702上。總線702將數(shù)據(jù)承載到主存儲器706,處理器704從主存儲器706檢索指令并且執(zhí)行指令。由主存儲器706接收的指令可以選擇性地在被處理器704執(zhí)行之前或之后存儲在存儲設備710上。

計算機系統(tǒng)700還包括耦接到總線702的通信接口718。通信接口718提供耦接到網(wǎng)絡鏈路720的雙向數(shù)據(jù)通信,網(wǎng)絡鏈路720被連接到本地網(wǎng)絡722。例如,通信接口718可以是綜合業(yè)務數(shù)字網(wǎng)(ISDN)卡、線纜調(diào)制解調(diào)器、衛(wèi)星調(diào)制解調(diào)器或者用于提供到對應類型的電話線的數(shù)據(jù)通信連接的調(diào)制解調(diào)器。作為另一示例,通信接口718可以是局域網(wǎng)(LAN)卡以提供到兼容的LAN的數(shù)據(jù)通信連接。無線鏈路也可以被實現(xiàn)。在任何這種實施方式中,通信接口718發(fā)送和接收承載有表示各種類型的信息的數(shù)字數(shù)據(jù)流的電信號、電磁信號或光信號。

網(wǎng)絡鏈路720典型地通過一個或多個網(wǎng)絡提供到其他數(shù)據(jù)設備的數(shù)據(jù)通信。例如,網(wǎng)絡鏈路720可以通過本地網(wǎng)絡722提供到主機計算機724或到由網(wǎng)絡服務提供商(ISP)726運營的數(shù)據(jù)裝置的連接。ISP 726又通過現(xiàn)在通常被稱為“互聯(lián)網(wǎng)”728的全球分組數(shù)據(jù)通信網(wǎng)提供數(shù)據(jù)通信服務。本地網(wǎng)絡722和因特網(wǎng)728都使用承載有數(shù)字數(shù)據(jù)流的電信號、電磁信號或光信號。通過各種網(wǎng)絡的信號和在網(wǎng)絡鏈路720上并通過通信接口718的信號是傳輸介質(zhì)的示例形式,這些信號承載有到計算機系統(tǒng)700的數(shù)字數(shù)據(jù)以及來自計算機系統(tǒng)700的數(shù)字數(shù)據(jù)。

計算機系統(tǒng)700可以通過網(wǎng)絡、網(wǎng)絡鏈路720和通信接口718來發(fā)送消息和接收包括程序代碼的數(shù)據(jù)。在互聯(lián)網(wǎng)示例中,服務器730可以通過互聯(lián)網(wǎng)728、ISP 726、本地網(wǎng)絡722和通信接口718來傳送用于應用程序的請求的代碼。

所接收的代碼可以如它被接收的那樣由處理器704執(zhí)行,和/或被存儲在存儲設備710或者其他非易失性存儲中以便以后執(zhí)行。

如本文所使用的,術語“一個”、“兩個”、“某個”和“特定”被用作命名約定以將查詢、計劃、表示、步驟、對象、設備或其他項彼此區(qū)分開,以使得這些項可以在它們被介紹之后被引用。除非在此另外指定,這些術語的使用不暗示所引用的項的順序、時序或任何其他特性。

8.0擴展和替代

在上面的說明書中,已經(jīng)參照隨著實施方式不同而不同的許多具體細節(jié)描述了本發(fā)明的實施例。因此,本發(fā)明是什么以及申請人意圖本發(fā)明是什么的唯一且排他的指示物是以權利要求發(fā)布的具體形式從本申請中發(fā)布的一組權利要求,包括任何后續(xù)補正。針對權利要求中所包含的術語,本文明確闡述的任何定義應當決定如權利要求中使用的這些術語的含義。因此,在權利要求中沒有明確表述的限制、要素、性質(zhì)、特征、優(yōu)點或屬性都不應當以任何方式限制這些權利要求的范圍。因此,說明書和附圖應被視為是說明性的而非限制性的。

9.0第一附加公開

本文所描述的主題的方面列舉在以下標號的條款中:

1.一種方法,包括:接收指定將特定值類型的值指派到多個容器中的特定容器的一個或多個較高級別的指令,其中所述多個容器表示用于在代碼塊的執(zhí)行期間維護一個或多個變量的數(shù)據(jù)結構,其中所述多個容器中的至少兩個容器具有不同的尺寸;基于根據(jù)所述特定值類型將一個或多個指派規(guī)則應用于所述一個或多個較高級別的指令,生成將所述值指派到所述特定容器的一個或多個較低級別的指令;執(zhí)行所述一個或多個較低級別的指令;其中所述方法由一個或多個計算設備執(zhí)行。

2.如條款1所述的方法,其中所述一個或多個指派規(guī)則包括以下中的一個或多個:限制哪些值類型能夠被指派到所述特定容器的約束,在向所述特定容器中加載所述值的拆箱表示或對保持所述值的第二容器的引用之間進行選擇的規(guī)則。

3.如條款2所述的方法,其中在向特定容器中加載所述值的所述拆箱表示或對保持所述值的第二容器的引用之間進行選擇的規(guī)則基于以下中的一項或多項:所述值是否是不可變的、所述值是否能夠適配在所述特定容器內(nèi)、所述值是否超出了特定的尺寸閾值、所述多個容器中的另一個容器是否已經(jīng)存儲了所述值、所述值的成分的性質(zhì)、或者所述一個或多個較低級別的指令將如何利用所述值。

4.如條款2-3中的任一項所述的方法,其中所述多個容器被存儲在為多個線程中的特定線程預留的存儲器位置中,并且所述第二容器在由所述多個線程共享的存儲器位置中位于所述多個容器的外部。

5.如條款2-4中的任一項所述的方法,其中所述約束基于以下中的一項或多項:(1)確定所述特定容器已經(jīng)被分配為適配一個或多個值類型,并且將對所述特定容器的指派限制為所述一個或多個值類型的值,(2)將對所述特定容器的指派限制為與所述特定容器共享尺寸的值或具有比所述特定容器小的尺寸的值,(3)將對所述特定容器的指派限制為一個或多個特定值類型直至接收到重置所述特定容器的指令。

6.如條款2-5中的任一項所述的方法,還包括:響應于確定要在所述特定容器中加載所述值的所述拆箱表示以及確定所述特定容器不能適配所述值,調(diào)整所述特定容器的尺寸以適配所述值。

7.如條款1-6中的任一項所述的方法,還包括:接收指定改變第二特定容器中存儲的第二值的成分的一個或多個第二較高級別的指令,其中所述第二值具有第二特定值類型;至少部分地基于與所述第二特定值類型相關聯(lián)的元數(shù)據(jù)來生成識別所述第二特定容器的與所述成分部分對應的部分的單個較低級別的指令;執(zhí)行所述單個較低級別的指令。

8.如條款2-7中的任一項所述的方法,其中識別所述第二特定容器的所述部分包括以下中的一項或多項:使用對應于所述第二特定值類型的值類型定義的字段定義來定位所述部分,使用所述值類型定義的訪問控制信息來實行對所述部分的訪問限制,或者基于所述值類型定義來執(zhí)行類型檢查。

9.如條款1-8中的任一項所述的方法,還包括:接收指定訪問第二特定容器中存儲的第二值的成分的一個或多個第二較高級別的指令,其中所述第二值具有第二特定值類型;基于與所述第二特定值類型相關聯(lián)的元數(shù)據(jù)來確定對所述成分的訪問是否應當是原子的;響應于確定對所述成分的訪問應當是原子的,確定所述成分是否存儲在不可變?nèi)萜髦?;響應于確定所述成分存儲在不可變?nèi)萜髦校刹惶峁┰颖WC的一個或多個第二較低級別的指令并且執(zhí)行所述一個或多個第二較低級別的指令;響應于確定所述成分沒有存儲在不可變?nèi)萜髦校x擇能夠提供對所述成分的原子訪問的一個或多個機制中的特定機制,基于所述特定機制生成提供原子保證的一個或多個第三較低級別的指令,以及執(zhí)行所述一個或多個第三較低級別的指令。

10.如條款2-9中的任一項所述的方法,其中所述第二值存儲在第一容器中,并且所述方法還包括:響應于確定所述成分沒有存儲在不可變?nèi)萜髦?,確定所述成分的訪問頻率是否超過訪問閾值;響應于確定所述成分的所述訪問頻率超過所述訪問閾值,將所述成分存儲在分開的第二容器中并且針對所述成分在所述第一容器中存儲對所述第二容器的引用。

11.如條款2-10中的任一項所述的方法,其中能夠提供對所述成分的原子訪問的所述一個或多個機制基于由所述一個或多個計算設備的一個或多個處理器支持的一組指令。

12.存儲有指令的一個或多個計算機可讀介質(zhì),所述指令當被一個或多個計算設備執(zhí)行時使得執(zhí)行如條款1-11中的任一項所述的步驟。

13.一種系統(tǒng),該系統(tǒng)包括一個或多個計算設備,所述一個或多個計算設備包括至少部分地由計算硬件實現(xiàn)的、被配置為實現(xiàn)如條款1-11中的任一項所述的步驟。

10.0第二附加公開

根據(jù)實施例,諸如當將Java或其他源代碼編譯為字節(jié)碼或在任何其他合適的編程環(huán)境中時,根據(jù)較高級別的指令生成較低級別的指令。較低級別的指令包括訪問諸如運行時數(shù)據(jù)區(qū)域的局部變量、棧元素、寄存器、虛擬寄存器和/或其他命名的虛擬變量的之類的容器內(nèi)的值的指令。容器具有變化的尺寸以便于例如能夠直接地而不是通過對堆或其他存儲器區(qū)域中的容器的引用來存儲具有可變尺寸的值。

較高級別的指令包括某個值類型的值。值可以是例如由若干成分組成的非原生的復合值,諸如Point或Complex。該某個值類型可以例如由類定義,其中該類的值是實例。響應于較高級別的指令,較低級別的指令可以被生成以將值或者(在一些情況中)對值的引用加載到尺寸可變化的容器之一。這種較低級別的指令的一個示例是本文所描述的vaload指令?;蛘撸^低級別的指令可以存儲、修改、移動和/或重置容器。在任何一種情況中,基于特定值類型以及基于與特定值類型相關的一個或多個指派規(guī)則來生成較低級別的指令。這種指派規(guī)則可以被配置為例如限制與維護支持可變尺寸的容器而非具有預定義的固定尺寸的容器相關聯(lián)的成本,和/或限制維護在容器之間復制的值的多個拷貝的成本。

在實施例中,指派規(guī)則可以包括例如一個或多個約束,在該一個或多個約束下,在方法的調(diào)用期間,不同的值類型可以被加載到容器中。在實施例中,這種約束的一個示例可以指定在方法的過程期間被加載到容器中的值可以具有最多一種數(shù)據(jù)類型或者數(shù)據(jù)類型的有限集合。因此,給定的容器可以僅保持容器最初被分配的值類型的值以及選擇地保持原生或引用的值。選擇性地,該約束可以持續(xù)至容器的類型被重置或者被指派的值被移動到其他地方為止。例如,“重置”指令將重置類型以及內(nèi)容,而“移動”指令將重置類型以及將內(nèi)容重新指派到另一個容器,諸如棧的頂部。移動操作將線性類型或所有權(ownership)類型的概念應用于解釋器效率。

在實施例中,另一示例性約束可以是被指派到容器的值必須全部具有如下值類型:該值類型被保證具有不大于指定尺寸的尺寸或者可替代地被保證具有與指定尺寸完全相同的尺寸。在實施例中,另一示例性約束可以是在方法的過程期間被記載到給定容器的值可以具有變化的數(shù)據(jù)類型,但是如果給定容器被用于存儲值類型,則它不能被用于存儲不同的類型(可選擇地,直至容器被重置)。

在實施例中,指派規(guī)則的另一示例是在將值的拆箱表示或者對保持值的外部容器的引用加載到容器中之間最優(yōu)地選擇的規(guī)則。這種規(guī)則可以考慮諸如外部容器或值的成分的性質(zhì)或較低級別的指令內(nèi)如何利用值之類的因素。例如,規(guī)則可以基于值在外部容器內(nèi)是否有效地是不可變的。在實施例中,指派規(guī)則的另一示例是關于當?shù)诙萜饕呀?jīng)包含第一容器的值的拷貝時將值加載到第一容器中的約束。任何其他合適的指派規(guī)則也可以同時或者替代地被利用。

根據(jù)實施例,在一組指令的驗證(諸如在解釋器解釋字節(jié)碼之前由字節(jié)碼驗證器進行的驗證)期間執(zhí)行某些步驟。例如,當驗證根據(jù)上文所描述的技術生成的較低級別的指令時,步驟可以被執(zhí)行。所述步驟包括識別將值加載到具有變化的尺寸的一組容器中的容器的指令。步驟還包括基于要被加載在容器中的值的值類型來驗證指令遵從一個或多個約束。在實施例中,約束可以包括上文所描述的指派規(guī)則和/或約束中的一個或多個。

根據(jù)實施例,當從較高級別的指令生成較低級別的指令時,改變某個值類型的值內(nèi)的字段的一個或多個較高級別的指令可被識別。值可以是例如潛在地具有多個不同成分字段的值類型的實例。本文描述了這種值類型的示例,諸如Point或Complex??梢源_定的是,在較低級別的指令的背景下,用于值的至少一個成分字段的數(shù)據(jù)將被集體存儲在單個容器內(nèi)。例如,字段可以被存儲為其對應的子值的拆箱表示,而不是對存儲對應的子值的其他容器的引用。響應于該確定,單個較低級別的指令被生成。這種較低級別的指令的示例是本文所描述的vput指令。

所生成的單個較低級別的指令被配置為命令解釋器識別容器的對應于字段的部分,諸如一個或多個位。單個較低級別的指令還被配置為命令解釋器根據(jù)一個或多個較高級別的指令改變該部分。識別和/或改變可以至少部分基于與值的值類型相關聯(lián)的元數(shù)據(jù)。例如,指令可以使得解釋器使用值類型的字段定義來定位該部分,和/或實行用于對應的值類型定義的訪問控制信息和類型檢查等。在實施例中,單個較低級別的指令命令解釋器在不使用指針來定位字段和/或不必發(fā)出打開值進入到其成分字段中的另一命令的情況下來執(zhí)行這些操作。

在實施例中,通過重新排序、合并或分開與彼此相關并且與可以讀取或寫入存儲在容器中的值或該值的至少一些成分字段的任何其他指令相關的兩個或更多個這種較低級別的指令的效果,選擇地生成較低級別的指令。這種效果的重新排序、合并或分開可以經(jīng)受保護存儲在容器中的值的每個成分字段以及作為整體存儲在容器中的值的一致性的規(guī)則。因此,技術可以包括使用分層的數(shù)據(jù)結構的嵌套存儲器模型,當對象拆分成值時,該數(shù)據(jù)結構可以拆分成更小的值并且最終一直向下拆分成成分原生和引用。

根據(jù)實施例,方法包括:當解釋諸如Java字節(jié)碼之類的指令時,識別用于插入較小的第一值作為較大的第二值的字段的指令。該指令可以是例如單個較低級別的指令,諸如上面生成的指令。第二值可以是例如具有被集體存儲在容器中的多個不同成分字段的經(jīng)定義的值類型的值。第一值可以是例如對應于字段的子值。在實施例中,確定第二值具有某個值類型。基于與某個值類型相關聯(lián)的元數(shù)據(jù),對應于字段的第二值的一部分被定位,并且第一值被加載到該部分中。這可以包括例如基于與某個值類型相關聯(lián)的值類型定義數(shù)據(jù)來實行訪問控制信息和類型檢查,和/或使用值類型定義數(shù)據(jù)來定位相關部分。在實施例中,通過重新排序、合并或分開兩個或更多個這種較低級別的指令的效果來選擇性生成較低級別的指令,諸如上文所描述的。

根據(jù)實施例,代碼可以訪問意欲是原子的值的字段。這種代碼可以包括例如諸如getfield或putfield之類的指令。由于例如其值是實例的值類型的定義中的聲明、或者當值被實例化時的聲明、和/或解釋器或編譯器的默認配置,值可以是原子的。響應于該代碼,編譯器或解釋器可以做出與決定在訪問字段時是否實現(xiàn)鎖定策略和/或實現(xiàn)哪個鎖定策略相關的一個或多個確定。

在實施例中,一種這樣的確定是字段是否為不可變的。例如,字段可以被局限于正在執(zhí)行的線程,字段可以是“凍結”的字段,和/或字段可以被聲明為是最終的。如果字段不可變,則可以生成在不鎖定的情況下訪問字段的指令。在實施例中,另一種這樣的確定是執(zhí)行硬件是否具有事務支持。如果是,則為了訪問字段生成對硬件的指令的事務版本,以便于確保訪問被以事務方式處理。

在實施例中,另一種這樣的確定是字段是否是頻繁改變的和/或值是否是復雜的或頻繁訪問的。如果是,則生成指令來將字段存儲在諸如通過指針在值內(nèi)引用的容器之類的分開的容器內(nèi),而不是直接將字段存儲在存儲值的容器內(nèi)。指令經(jīng)由分開的容器訪問字段。在實施例中,另一種這樣的確定是值是否為已經(jīng)被劃分為子值的大值。值可以實際地被劃分并且存儲在分開的容器中,或者出于鎖定的目的值可以在邏輯上被劃分。如果值是已經(jīng)被劃分為子值的大值,則通過鎖定字段在其中駐留的子值來生成訪問字段的指令。在實施例中,另一種這樣的確定是值本身是否為另一個值的字段。如果是,則在此基礎上選擇鎖定策略。任何其他合適的確定可以被同時或者替代地做出。在實施例中,做出一系列的確定。從資源的視角被估計為最便宜的確定首先被執(zhí)行,而其他確定僅在需要的時候執(zhí)行。

在其他方面,公開了用于實現(xiàn)本文所描述的技術的計算設備的系統(tǒng)和計算機可讀介質(zhì)。

當前第1頁1 2 3 
網(wǎng)友詢問留言 已有0條留言
  • 還沒有人留言評論。精彩留言會獲得點贊!
1
开平市| 宜兰县| 安康市| 岳阳县| 长治县| 张家川| 炉霍县| 乡城县| 刚察县| 陈巴尔虎旗| 晋中市| 眉山市| 新和县| 乳山市| 中宁县| 九龙县| 焦作市| 新密市| 万安县| 扶风县| 马关县| 鹤峰县| 贵溪市| 大新县| 吉水县| 江达县| 凌云县| 北宁市| 离岛区| 准格尔旗| 崇信县| 鹤壁市| 洮南市| 梅河口市| 恩平市| 睢宁县| 镇原县| 县级市| 阳信县| 乌兰县| 天长市|