CN101908001A - 具有协作对象的修改后的计算机架构 - Google Patents
具有协作对象的修改后的计算机架构 Download PDFInfo
- Publication number
- CN101908001A CN101908001A CN2010102473092A CN201010247309A CN101908001A CN 101908001 A CN101908001 A CN 101908001A CN 2010102473092 A CN2010102473092 A CN 2010102473092A CN 201010247309 A CN201010247309 A CN 201010247309A CN 101908001 A CN101908001 A CN 101908001A
- Authority
- CN
- China
- Prior art keywords
- computing machine
- machine
- application program
- constant
- index
- Prior art date
- Legal status (The legal status is an assumption and is not a legal conclusion. Google has not performed a legal analysis and makes no representation as to the accuracy of the status listed.)
- Granted
Links
Images
Classifications
-
- G—PHYSICS
- G06—COMPUTING; CALCULATING OR COUNTING
- G06F—ELECTRIC DIGITAL DATA PROCESSING
- G06F9/00—Arrangements for program control, e.g. control units
- G06F9/06—Arrangements for program control, e.g. control units using stored programs, i.e. using an internal store of processing equipment to receive or retain programs
- G06F9/46—Multiprogramming arrangements
- G06F9/52—Program synchronisation; Mutual exclusion, e.g. by means of semaphores
-
- G—PHYSICS
- G06—COMPUTING; CALCULATING OR COUNTING
- G06F—ELECTRIC DIGITAL DATA PROCESSING
- G06F9/00—Arrangements for program control, e.g. control units
- G06F9/06—Arrangements for program control, e.g. control units using stored programs, i.e. using an internal store of processing equipment to receive or retain programs
- G06F9/30—Arrangements for executing machine instructions, e.g. instruction decode
-
- G—PHYSICS
- G06—COMPUTING; CALCULATING OR COUNTING
- G06F—ELECTRIC DIGITAL DATA PROCESSING
- G06F15/00—Digital computers in general; Data processing equipment in general
- G06F15/16—Combinations of two or more digital computers each having at least an arithmetic unit, a program unit and a register, e.g. for a simultaneous processing of several programs
Landscapes
- Engineering & Computer Science (AREA)
- Theoretical Computer Science (AREA)
- Software Systems (AREA)
- Physics & Mathematics (AREA)
- General Engineering & Computer Science (AREA)
- General Physics & Mathematics (AREA)
- Computer Hardware Design (AREA)
- Multi Processors (AREA)
- Stored Programmes (AREA)
- Devices For Executing Special Programs (AREA)
Abstract
本发明公开了一种修改的计算机架构,其使得应用程序(50)能够在多个计算机(M1、...Mn)上同时运行。每个计算机处的共享存储器被以修改和/或覆写来更新,以便使所有存储器读请求在本地得到满足。在初始程序加载(75)期间,或相似过程期间,识别导致存储器被重写或操纵的指令(92)。此外,公开了JAVA语言类和对象的初始化(162,163),这样所有计算机的所有存储器位置以相同的方式被初始化。还公开了JAVA语言类和对象的终结化(162,163),这样仅当不再需要所有机器上的最后的类或对象时,才会发生终结化。
Description
本发明申请为2005年4月22日提交的申请号为200580018405.7、发明名称为“具有协作对象的修改后的计算机架构”的发明申请的分案申请。
技术领域
本发明涉及计算机,具体而言,涉及一种修改的计算机架构,其使应用程序能够在经由通信网络互连的多个计算机上同时运行。
背景技术
自从计算机及计算出现以来,所编写的计算机软件是在单个机器上运行的。如图1所示,所示的单个现有技术机器1包括经由总线4连接至存储器3的中央处理单元CPU 2。连接至总线4的还有单个机器1的其他功能单元,如屏幕5、键盘6和鼠标7。
对该机器1性能的基本限制在于:数据由CPU 2来处理,而这些处理结果必须通过总线4来传送。总线4经受很多问题,包括由想要获取对总线的访问的单元所形成的所谓总线“队列”、竞争问题等。在某种程度上,这些问题可通过各种策略来缓解,所述策略包括高速缓冲存储器,但是,这样的策略没有例外地会增加机器1的管理开销。
自然,多年来,为了改善机器性能,人们进行了各种尝试。一种方法是使用对称的多个处理器。该现有技术方法已用于所谓的“超级”计算机中,如图2中示意性示出的。这里,多个CPU 12连接至全局存储器13。而在CPU 12和存储器13间的通信中也出现了瓶颈。该过程被称作“单***映像”。仅有一个应用以及用于该应用的分布在全局存储器上的存储器的一个完整拷贝。该单个应用可完全透明地从任何存储器位置读取或写入任何存储器位置(即共享)。
当存在经由网络互连的多个这样的机器时,这是通过利用针对单个机器编写的单个应用并将所需存储器资源分割成多个部分来实现的。然后,这些部分分布在多个计算机上,以形成可由所有CPU 12访问的全局存储器13。该过程依赖于对运行的单个应用程序遮蔽或隐藏所述的存储器分割。当一个机器上的一个CPU必须(经由网络)访问物理上位于不同机器中的存储器位置时,性能会劣化。
尽管超级计算机已在获取高计算速率方面在技术上取得了成功,但是其在商业上是不成功的,因为其固有的复杂性使得其制造和管理极其昂贵。特别是,单***映像的概念从未能够应用于“日用”(大量生产的)计算机和网络。特别是,单***映像的概念仅仅实际应用于经由很快速的(因此很昂贵的)网络互连的很快速的(同样昂贵的)计算机上。
通过使用多个机器来增加计算机能力的另一可能性来自现有技术的分布式计算概念,如图3中示意性所示。在该已知设置中,单个应用程序(Ap)由其作者(或熟悉该应用程序的另一程序员)分割成多个离散任务,以便在例如3个机器上运行,在图3中,n为整数3。这里的意图是,机器M1...M3的每个运行整个应用的不同的三分之一,且意图是使施加于各机器的负载大体相等。所述机器经由网络14来通信,所述网络14可以各种形式来提供,如通信链路、互联网、内联网、局域网等。这种网络14的运行速度一般比各机器M1、M2等的每个的总线4的运行速度慢一个量级。
分布式计算具有多个缺点。第一,分割应用是一项困难的工作,而且必须人工完成。第二,网络14上的通信数据、部分结果、结果等是一种管理开销。第三,分割的需要使利用更多机器来扩展变得极其困难,因为已分割成例如3部分的应用不能在4个机器上很好地运行。第四,在其中一个机器不能工作时,会实质上降低整个***的总体性能。
另一现有技术设置已知为通过“簇(cluster)”的网络计算,如图4中示意性所示。在该方法中,整个应用被载入每个机器M1、M2、...、Mn上。每个机器都与公共数据库通信,但不与其他机器直接通信。尽管每个机器运行同一应用,但是每个机器进行不同的“工作”并仅使用其自己的存储器。这有点类似于多个窗口每个均向公众出售火车票。该方法确实可行、可升级,而主要具有的缺点是难以管理网络。
在计算机语言如JAVA和MICROSOFT.NET中,有程序员应对的两种主要类型的结构。在JAVA语言中,它们称作对象和类。每次创建对象时,均有称作“<init>”的初始化例程运行。同样,每次加载类时,均有称作“<clinit>”的初始化例程运行。其他语言使用不同的术语,但利用相似的概念。
然而,一旦不再需要对象或类时,却没有相当的“清理”或删除例程来删除对象或类。相反地,该“清理”以后台的方式不引人注意地发生。
另外,在任何计算机环境中都需要获取和释放锁定(lock),以便能够使用这样的资产、资源或结构,而避免应用程序的不同部分试图同时使用同一资源。在JAVA环境中,这称作同步。在JAVA中,这是通过“monitorenter”和“monitor exit”指令或例程来实现的。其他语言使用不同的术语,但利用相似的概念。
发明内容
本发明公开了一种计算环境,其中一个应用程序同时在多个计算机上运行。在这种环境中,需要保证上述初始化、清理和同步过程在所有机器上以一致而协作的方式来运行。该协作目的即是本发明的起源。
根据本发明的第一方面,公开了一种多计算机***,该多计算机***具有各被编写为仅在单个计算机上运行但却在经由通信网络互连的多个计算机上同时运行的至少一个应用程序,其中创建了同样多个基本相同的对象,每个对象在对应的计算机中,且每个具有基本相同的名称,其中所述相同命名的对象每个的初始内容是基本上相同的,其中,当所述多个计算机的每个不再需要引用其对应的对象时,所有所述相同的对象被全体删除,并且其中,所述***包括可应用于所有所述计算机的锁定装置,其中想要利用其中的被命名的对象的任一计算机从所述锁定装置获取授权锁定,所述授权锁定允许所述利用,并防止所有其他计算机利用它们对应的被命名的对象,直到所述授权锁定被放弃。
根据本发明的第二方面,公开了一种在多个计算机上同时运行至少一个各被编写为仅在单个计算机上运行的应用程序的方法,所述计算机借助于通信网络来互连,所述方法包括下列步骤:
i)创建同样多个基本相同的对象,每个对象在对应的计算机中,且每个具有基本相同的名称,
ii)创建所述的相同命名的对象的每个的初始内容,所述初始内容基本上相同,
iii)当所有所述多个计算机不再需要引用其对应的对象时,全体删除所有所述的相同对象,以及
iv)要求其中想要利用命名对象的所述计算机中的任何一个去获取授权锁定,该授权锁定允许所述利用,并防止所有其他计算机利用它们的对应的被命名的对象,直到所述授权锁定被放弃。
根据本发明的一方面,公开了一种多计算机***,具有同时运行在多个计算机上的至少一个应用程序,其中所述多个计算机通过通信网络来互连,其中创建同样多个基本上相同的对象,每个所述对象在对应的计算机中且各具有基本上相同的名称,其中每个所述的相同命名的对象的初始内容是基本上相同的,其中当所述多个计算机的每个不再需要引用其对应的对象时,所有所述相同的对象被全体删除,并且其中所述***包括可应用于所有所述计算机的锁定装置,其中想要利用其中所命名的对象的任何计算机从所述锁定装置获取授权锁定,所述锁定装置允许所述利用,并防止所有其他计算机利用其对应的所命名的对象,直到所述授权锁定被放弃。
其中,所述锁定装置包括获取锁定例程和释放锁定例程,且两个例程均包括在对所述应用程序的修改中,其中所述应用程序运行在所有所述计算机上。
其中,所述锁定装置进一步包括共享表,该共享表列出由任何所述计算机所使用的所述命名的对象、每个所述对象的锁定状态以及任何未决的锁定获取的队列。
其中,所述锁定装置位于不运行所述应用程序并连接到所述通信网络的附加计算机内。
其中,每个所述计算机都包括分布式运行时间装置,其中每个所述计算机的分布式运行时间装置能够与所有其他计算机通信,由此如果运行在所述计算机之一上的所述应用程序的部分在该计算机中创建对象,则所创建的对象由所述的一个计算机的分布式运行时间装置传播到所有其他计算机。
其中,每个所述计算机都包括分布式运行时间装置,其中每个所述计算机的分布式运行时间装置能够与所有其他计算机通信,由此如果运行在所述计算机之一上的所述应用程序的部分不再需要引用该计算机中的对象,则不被引用的对象的标识由所述的一个计算机的分布式运行时间装置传送至可由所有其他计算机访问的共享表。
其中,通过***初始化例程在加载之前、期间或之后对每个所述应用程序进行修改,以对所述应用程序在其处创建对象的每个实例进行修改,所述初始化例程将一个计算机新创建的每个对象传播到所有所述其他计算机。
其中,所述应用程序是根据从下列过程构成的组中所选出的过程来修改的:加载时的重新编译、加载前的预编译、加载前的编译、刚好适时的编译、在加载后且在应用程序相关部分执行之前的重新编译。
其中,所述被修改的应用程序根据从下列构成的组中所选出的过程被传送到所有所述计算机:主/从传送、分支传送和级联传送。
其中,分配给所述应用程序或每个所述应用程序的本地存储器容量基本上相同,且对所述应用程序或每个所述应用程序可用的总存储器容量是所述的所分配的存储器容量。
其中,所有所述计算机包括分布式更新装置,每个所述分布式更新装置以明显小于本地存储器读取速率的数据传送速率经由所述通信链路来通信。
其中,所述计算机的至少一些由不同制造商制造和/或具有不同的操作***。
根据本发明的另一方面,公开一种在多个计算机上同时运行至少一个应用程序的方法,所述计算机借助于通信网络来互连,所述方法包括下列步骤:(i)创建同样多个基本上相同的对象,每个所述对象在对应的计算机中且具有基本上相同的名称,(ii)创建每个所述的相同命名的对象的基本上相同的初始内容,(iii)当所有所述多个计算机不再需要引用其对应的对象时,所有所述的相同对象被全体删除,以及(iv)要求想要利用其中所命名的对象的任何所述计算机获取授权锁定,所述授权锁定允许所述利用,并防止所有其他计算机利用其对应的被命名的对象,直到所述授权锁定被放弃。
根据本发明一个实施例的该方法进一步包括下列步骤:(v)如果运行在所述计算机之一上的所述应用程序的部分在该计算机中创建对象,则将所创建的对象经由所述通信网络传播到所有其他计算机。
根据本发明一个实施例的该方法进一步包括下列步骤:(vi)通过***初始化例程,在加载之前、期间或之后对每个所述应用程序进行修改,以对所述应用程序在其处创建对象的每个实例进行修改,所述初始化例程将一个计算机创建的每个对象都传播到所有所述其他计算机。
根据本发明一个实施例的该方法进一步包括下列步骤:(vii)为每个所述计算机提供分布式运行时间装置,以经由所述通信网络在所述计算机之间通信。
根据本发明一个实施例的该方法进一步包括下列步骤:(viii)提供可由每个所述分布式运行时间装置访问的共享表,并且其中存储不再要求访问对象的任何计算机的标识、连同该对象的标识。
根据本发明一个实施例的该方法进一步包括下列步骤:(ix)使计数器装置与所述共享表关联,所述计数器装置存储对不再要求访问所述对象的所述计算机的数量的计数。
根据本发明一个实施例的该方法进一步包括下列步骤:(x)提供附加计算机,在所述附加计算机上不运行所述的共享程序,并且所述附加计算机容纳所述共享表和计数器,所述附加计算机连接到所述通信网络。
根据本发明一个实施例的该方法进一步包括下列步骤:(xi)提供可由每个所述分布式运行时间装置访问的共享表,并且其中存储当前须访问对象的任何计算机的标识、连同该对象的标识。
根据本发明一个实施例的该方法进一步包括下列步骤:(xii)使计数器装置与所述共享表关联,所述计数器装置存储对寻求对所述对象的访问的所述计算机的数量的计数。
根据本发明一个实施例的该方法进一步包括下列步骤:(xiii)提供附加计算机,所述的共享程序不在所述附加计算机上运行,并且所述附加计算机容纳所述共享表和计数器,所述附加计算机连接到所述通信网络。
根据本发明的再一方面,公开了多个计算机,经由通信网络互连,并可操作以保证对在所述多个计算机上同时运行的应用程序的一致的初始化,所述多个计算机被编程来执行如上所述的方法。
根据本发明的一个方面,公开了一种多计算机***,所述多计算机***具有至少一个应用程序,所述应用程序在通过通信网络互连的多个计算机上同时运行,其中所述应用程序的不同部分基本上同时在所述多个计算机中不同的计算机上执行,其中对于每个所述部分,创建同样多个基本上相同的对象,每个所述对象在对应的计算机中,且其中每个所述计算机的所有读请求仅从读在请求计算机中创建的对象来满足。
根据本发明的另一个方面,公开了一种在多个计算机上同时运行至少一个应用程序的方法,所述计算机借助于通信网络来互连,所述方法包括以下步骤:(i)在所述计算机中的不同计算机上执行所述应用程序的不同部分,以及对于每个所述部分,创建同样多个基本上相同的对象,所述对象每个在对应的计算机中;以及(ii)通过仅从读在请求计算机中创建的对象来满足每个所述计算机的所有读请求。
根据本发明的再个方面,公开了一种单个计算机,被布置为与至少一个其他同样的计算机合作以形成上面所述的多计算机***。
根据本发明的其他方面,公开了一种计算机程序产品,该计算机程序产品包括一组程序指令,该程序指令存储于存储介质中,并可操作以允许多个计算机执行上述方法。
附图说明
下面将参考附图来说明本发明的实施例,在附图中:
图1示意性示出了传统计算机的内部架构,
图2示意性示出了已知的对称多处理器的内部架构,
图3示意性示出了现有技术的分布式计算,
图4示意性示出了现有技术的利用簇的网络计算,
图5是根据本发明第一实施例的多个机器运行同一应用程序的示意性框图,
图6示意性示出了设置用于运行JAVA代码并由此构成JAVA虚拟机的现有技术计算机,
图7与图6相似,但示出了根据本发明优选实施例的对代码的初始加载,
图8与图5相似,但示出了各以图7所示的方式来运行JAVA代码的多个计算机的互连,
图9是在将同一应用加载到网络中每个机器上的期间所遵循的过程的流程图,
图10的流程图示出了与图9的过程相似的修改的过程,
图11示意性示出了利用存储器更新的第一实施例在图8的机器上执行多个线程处理。
图12的示意图与图11相似,但示出了另一实施例,
图13示出了用于图8的计算机的多线程存储器更新,
图14示意性示出了设置用于以JAVA代码运行并由此构成JAVA虚拟机的现有技术计算机,
图15示意性示出了运行应用程序并由附加的服务器机器X来提供服务的n个机器,
图16的流程图示出了初始化例程的修改,
图17的流程图示出了初始化例程的继续或中止,
图18的流程图示出了发送到服务器机器X的问询,
图19是服务器机器X对图18的请求作出响应的流程图,
图20的流程图示出了针对<clinit>指令的修改的初始化例程,
图21的流程图示出了针对<init>指令的修改的初始化例程,
图22的流程图示出了“清理”或终结化例程的修改,
图23的流程图示出了终结化例程的继续或中止,
图24的流程图示出了发送到服务器机器X的问询,
图25是服务器机器X对图24的请求作出响应的流程图,
图26的流程图示出了monitor enter和exit例程的修改,
图27的流程图示出了处理机器在请求获取锁定中所遵循的过程,
图28的流程图示出了请求释放锁定,
图29是服务器机器X对图27的请求作出响应的流程图,
图30是服务器机器X对图28的请求作出响应的流程图,
图31示意性示出了互连以同时运行多个应用的两个膝上计算机,其中两个应用在单个计算机上运行,
图32的视图与图31相似,但示出了其中在每个计算机上运行一个应用的图31的装置,
图33的视图与图31和32相似,但示出了其中两个应用同时在两个计算机上运行的图31的装置。
本说明书包括附件A、B、C和D,这些附件提供了实际程序的片段,所述程序的片段可实施所述实施例的各方面。附件A涉及字段,而附件B涉及初始化。附件C涉及终结化。附件D涉及同步。
具体实施方式
结合图5,根据本发明的一个优选实施例,单个应用程序50可在经由网络53通信的多个机器M1、M2...Mn上同时运行。如下文中将变得明显的,机器M1、M2...Mn中的每个在每个机器M1、M2...Mn上运行同一应用程序50,因此所有机器M1、M2...Mn均具有相同的应用代码和数据50。同样,机器M1、M2...Mn中的每个在每个机器M1、M2...Mn上运行相同的(或基本上相同的)修改器51,因此所有机器M1、M2...Mn均具有相同的(或基本上相同的)修改器51,其中机器M2的修改器被指定为51/2。此外,在应用50被加载于每个机器M1、M2...Mn上的过程中,或在应用50在每个机器M1、M2...Mn上被执行之前,每个应用50已由对应的修改器51根据相同的规则(或基本上相同的规则,因为在每个修改器51/1...51/n内允许小的优化改变)进行了修改。
作为上述设置的结果,如果机器M1、M2...Mn中的每个都具有例如10MB的共享存储器容量,那么对每个应用50可用的总共享存储器不是如可能所预期的那样为10n MB,而是仅仅10MB。然而,这如何导致改善的运行将在下文中变得明显。自然,机器M1、M2...Mn中的每个具有非共享的存储器容量。机器M1、M2...Mn中的非共享存储器容量一般近似相等,但不一定必须如此。
从现有技术已知,通过创建图6中示意性示出的虚拟机以特定应用语言来运行机器(由不同制造商之一生产,并具有以各种不同的语言之一来运行的操作***)。图6的现有技术设置具有以Java语言编写并在Java虚拟机61内执行的应用50的形式。因此,当应用想要采用的语言是语言JAVA时,能够运行JAVA代码的JAVA虚拟机就被创建,而不管机器制造商及机器内部细节。更多细节参见美国SUN Microsystems Inc.的T.Lindholm&F.Yellin的“The JAVA Virtual Machine Specification”第二版。
根据本发明的优选实施例,通过提供如图7所示的方便地称作“分布式运行时间”或DRT 71的附加设施,对图6的该公知的现有技术设置进行修改。在图7中,应用50经由分布式运行时间***71通过箭头75所指的加载过程被加载到Java虚拟机72上。分布式运行时间***可在分布式计算环境(DCE)名下从开放软件基金会(Open Software Foundation)获得。特别是,分布式运行时间71在JAVA应用50的箭头75所指的加载过程期间投入运行,以便初始地创建JAVA虚拟机72。加载期间的操作顺序将在下文中结合图9来描述。
图8示出了利用JAVA虚拟机的对图5设置的修改形式,所述虚拟机的每个如图7中所示。明显的是,同一应用50再次加载到每个机器M1、M2...Mn上。但是,由箭头83指示的每个机器M1、M2...Mn间的通信(尽管通过机器硬件来物理地路由)由每个机器内的各个DRT 71/1...71/n来控制。因此,实际上,这可概念化为经由网络73彼此通信的DRT 71/1...71/n,而不是机器M1、M2...Mn本身。
现在转到图7和图9,在加载过程75期间,对被加载来创建JAVA虚拟机72的程序50进行修改。该修改在图9的90开始,并涉及对正在加载的应用50中的所有存储器位置(JAVA中称作字段-但在其他语言中使用相当的术语)进行检测的初始步骤91。对于步骤92和93中的后续处理需要对这样的存储器位置进行标识。在加载过程75期间,DRT 71创建如此标识的所有存储器位置的列表,JAVA字段通过对象和类来列表。易变字段和同步字段二者均被列出。
修改过程的下一阶段(图9中标记为92)是在可执行的应用代码中搜索,以便定位每个这样的处理活动,该处理活动对与步骤91所产生的列表对应的字段值进行操作和改变,且因此写入到字段,使得对应存储器位置的值发生改变。当检测到这种改变字段值的操作(典型地为JAVA语言中的putstatic或putfield)时,通过步骤93将“updating propagation routine(更新传播例程)”***于程序中的该处,以保证将字段值改变通知到所有其他机器。之后,加载过程如图9的步骤94所示以正常方式继续。
图10示出了加载期间的初始修改的另一形式。这里,起始和列表步骤90和91以及搜索步骤92与图9中相同。但是,不是如步骤93那样***“updating propagation routine(更新传播例程)”(其中处理线程执行该更新),而是在步骤103中***“alert routine(告警例程)”。“alert routine(告警例程)”指示未在处理中使用的或被分配给该DRT的一个或多个线程执行必要的传播。该步骤103是一个导致较低开销的较快的替选方法。
一旦加载过程期间发生了该初始修改,则发生图11和12中所示的多线程处理操作的任一个。如图11中可见,包含线程111/1...111/4的机器上的多线程处理110正在发生,而第二线程111/2(在该示例中)的处理导致线程111/2在步骤113获知字段值的改变。在该阶段,该线程111/2的正常处理在步骤114被中断,而同一线程111/2经由网络53将在步骤113中发生的被改变的字段的标识和改变的值通知给所有其他机器M2...Mn。在通信过程的结尾,线程111/2然后在步骤115继续处理,直到发生字段值改变的下一实例。
在图12中所示的另一设置中,一旦线程121/2在步骤113获知字段值的改变,其指示DRT处理120(如步骤125和箭头127所示),分配给DRT处理120的另一(或多个)线程121/1要根据步骤128经由网络53将步骤113所检测到的改变的字段的标识和改变的值传播到所有其他机器M2...Mn。该操作可以快速执行,因此,如步骤125所示的,在线程111/2继续步骤115中的处理之前,初始线程111/2的处理仅被瞬时中断。已被通知了所述改变(如箭头127所示)的另一线程121/1然后如步骤128所示经由网络53将该改变传送给每个其他机器M2...Mn。
图12的这第二种设置更好地利用了各线程111/1...111/3和121/1的处理能力(一般而言,这些线程并不被同等地要求),而且给予了较好的、具有可增加大小的“n”的缩放性(n是大于或等于2的整数,表示连接至网络53并同时运行应用程序50的机器总数)。不论使用哪种设置,改变的字段和标识及步骤113中所检测的值均被传播到网络上的所有其他机器M2...Mn。
这示于图13中,其中DRT 71/1及图12中的其线程121/1(图13中以步骤128来表示)经由网络53将所列的、在图12的步骤113通过机器M1中的处理所产生的存储器位置的标识和改变的值传播到每个其他机器M2...Mn。
通过接收来自网络53的标识和值的对、并将新值写入本地对应的存储器位置中,每个其他机器M2...Mn执行图13中步骤135和136所示的针对机器Mn的动作。
在利用分布式软件的图3的现有技术设置中,通过互连所述机器的网络,允许从一个机器软件到物理地位于另一机器上的存储器进行访问。但是,这样的存储器访问可导致机器中央处理单元的106-107个循环的量级的处理延迟。这很大程度上解释了多互连机器的降低的性能。
然而,在上述结合图8的本发明的设置中,可以理解的是,数据的所有读取均可在本地得到满足,因为所有字段的当前值均存储在执行该处理的机器上,所述处理产生读取存储器的命令。这样的本地处理可在中央处理单元的102-103个循环内得到满足。因此,实际上,基本上没有等待包括读取的存储器访问。
然而,大多数应用软件频繁地读取存储器,而相对不那么频繁地写入存储器。结果,与存储器被读取的速率相比,写入或重写存储器的速率相对较慢。由于这种对存储器写入或重写的慢的需求,可经由不昂贵的日常网络53以相对低的速度来持续更新字段,但该低速度足以满足应用程序对写入存储器的需求。结果是,图8的设置的性能大大优于图3的性能。
在与上述有关的另一实施例中,改变的字段的标识和值可被分组成批,以便进一步降低对互连各机器的网络53的通信速度的要求。
对本领域普通技术人员也是明显的是,在由每个DRT 71在初始记录字段时所创建的表中,对于每个字段有一个在整个网络中通用的且网络可辨别的名称或标识。但是,在各个机器中,与给定的命名字段对应的存储器位置将随时间变化,因为每个机器将根据其自己的内部进程逐步地在不同位置存储改变的字段值。因此,每个DRT中的表将通常具有不同的存储器位置,而每个全局“字段名称”将具有存储在不同存储器位置中的相同“字段值”。
对于本领域普通技术人员来说也明显的是,在加载过程中,应用程序的上述修改可通过下列多至5种方式来完成:
(i)加载时的重新编译,
(ii)在加载前通过预编译过程
(iii)加载前的编译
(iv)“正好及时(just-in-time)”的编译,或
(v)加载后的重新编译(但是(或例如)在分布式环境中的相关或对应的应用代码执行前)。
传统上,术语“编译”隐含代码或语言的改变,例如从源代码到目标代码或一种语言到另一种的改变。在本说明书中清楚的是,术语“编译”(及其语法上的等效)的使用并不如此受限,而亦可包括或包含同一代码或语言内的修改。
在第一实施例中,特定的机器,如机器M2,将应用代码加载于其自身上,对其进行修改,然后(顺序地或同时)以修改的代码加载每个其他机器M1、M3...Mn。在可称作“主/从”的该设置中,每个机器M1、M3...Mn加载机器M2所给予的内容。
在另一实施例中,每个机器接收应用代码,但在该机器上对其进行修改并加载修改的代码。这使得每个机器执行的修改有些许不同,基于其架构和操作***被优化,但仍与其他相似的修改是一致的。
在另一设置中,特定机器如M1加载未修改的代码,而所有其他机器M2、M3...Mn进行修改以删除原始应用代码并加载修改的版本。
在所有实例中,供给可以有分支(即M2直接供给M1、M3、M4等的每个)或可以是级联或按顺序的(即M2供给M1,然后M1供给M3,M3再供给M4,依此类推)。
在又一实施例中,机器M1至Mn可将所有加载请求发送给未运行应用程序的附加机器(未示出),该附加机器通过上述方法的任一种来进行修改,并将修改的例程返回给机器M1至Mn的每个,然后机器M1至Mn在本地加载修改的例程。在这种设置中,机器M1至Mn将所有加载请求发送到该附加机器,该附加机器将修改的例程返回给每个机器。该附加机器进行的修改可包括本发明的范围之内所覆盖的任一修改。
计算领域的普通技术人员会知道用于创建计算机代码中的修改的至少4种技术。第一种是以原始(源)语言进行的修改。第二种是将原始代码(如JAVA)转换成中间表示(或中间语言)。一旦发生转换,就进行修改,然后再反向转换。这给出修改的JAVA代码的期望结果。
第三种可能性是(直接或经由上述中间语言)转换成机器代码。然后在加载和执行前对机器代码进行修改。第四种可能性是将原始代码转换成中间表示,然后对中间表示进行修改,随后转换成机器代码。
本发明涵盖所有4种修改例程,也涵盖2种、3种或甚至4种所述例程的组合。
现在转到图4,示出了作为JAVA虚拟机运行的单个现有技术计算机的示意图。以这种方式,(由各制造商的任一个来生产并具有以各种不同语言的任一种来操作的操作***的)机器能以应用程序50的特定语言来运行,在该实例中为JAVA语言。也就是说,JAVA虚拟机72能够运行JAVA语言的代码50,并利用JAVA架构,而不管机器制造商和机器的内部细节。
在JAVA语言中,初始化例程<clinit>仅在加载给定类文件50A时发生一次。但是初始化例程<init>频繁发生,例如,每次创建新对象50X、50Y和50Z时都发生。此外,类是在对象前加载的,这样在图14所示的具有单个类50A和三个对象50X-50Z的应用程序中,首先加载第一类50A,然后加载第一对象50X,然后加载第二对象50Y,最后加载第三对象50Z。这里,如图14中所示,仅有单个计算机或机器72,于是要在加载过程期间工作的初始化例程的运行中没有出现冲突或不一致。
但是,在图8(还有图31-33)所示的设置中,提供了多个单独的计算机或机器M1、M2...Mn,其每个经由通信网络53来互连,且其每个被提供有修改器51并加载有普通应用程序50。实质上,修改器51用来复制各机器M1、M2...Mn的每个上的相同存储器结构和内容。因此结果是,在这种计算环境中,有必要保证各机器M1、M2...Mn的每个以一致的方式来初始化。图5的修改器51的修改功能由图8中的DRT 71来提供。
为了保证一致的初始化,应用程序50被仔细检查,以便检测定义初始化例程的程序步骤。该仔细检查可在加载前、或加载过程75期间、或甚至在加载过程75之后(但在相关对应的应用代码执行之前)发生。编译过程可这样理解:即术语编译通常涉及代码或语言上的改变,如从源代码到目标代码或从一种语言到另一种的改变。但是,在本实例中,术语“编译”(及其语法上的等效)并不受限于此,而是也可包含同一代码或语言中的修改。
结果,在上述仔细检查中,初始地查找<clinit>例程,当找到时,***修改代码(一般是几个指令),以便引起被修改的<clinit>例程的发生。该被修改的例程要将类50A加载到机器之一上,例如JVM#1上,并告知其他机器M2...Mn存在这样的类50A及其当前状态。存在可执行这种修改和加载的几种不同的模式。
因此,在一个模式中,加载机器(在本例中是JVM#1)上的DRT 71询问所有其他机器的DRT 71/2...71/n是否已经初始化了第一类50A。如果对该问题的回答为肯定,则关断或禁止正常的初始化过程。如果回答为否,则进行正常的初始化过程,而且在该过程期间产生的结果的变化将传送给所有其他机器,如图8中的箭头83所示。
每次要加载对象如50X、50Y或50Z时会发生相似的过程。如果在调查后DRT 71/1没有察觉到正在考虑的特定对象如对象50Y已经加载到其他机器M2...Mn上,那么,DRT 71/1运行对象初始化例程,并将等效对象(可方便地称作对等对象)连同初始值的拷贝一起加载到其他机器M2...Mn的每个上。但是,如果DRT 71/1确定正在考虑的对象50Y已经存在于其他机器上,则禁止正常的初始化功能,并利用当前值的拷贝来创建本地拷贝。同样,存在用于产生期望结果的各种方式。
如图15中所示,提供了对图8的通用设置的修改,其中机器M1、M2...Mn如前所述,并在所有机器M1、M2...Mn上同时运行同一应用程序(或多个程序)50。但是,以提供服务器机器X的方式对前述设置进行了修改,所述服务器机器X能够方便地提供管家(housekeeping)功能,特别是结构、资产和资源的初始化、清理和/或同步。因为其计算负载低,所以这种服务器机器X可以是低价值的日常计算机,如PC。如图15的虚线所示,为了备份的目的,可提供两个服务器机器X和X+1,以便提高***的总体可靠性。当提供两个这种服务器机器X和X+1时,它们优选地作为一个簇中的双重机器来工作。如图15的虚线所示,附加机器X+1是可选的。
提供服务器机器X不是必须的,因为其计算可以分布在机器M1、M2...Mn上。可替换地,一个机器操作的数据库(在主/从型操作中)可用于所述的管家功能。
图16示出了初始化所要遵循的优选通用过程。在加载步骤161已经开始后,按照顺序考虑待执行的指令,并检测所有初始化例程,如步骤162所示。在JAVA语言中,这些为<init>和<clinit>例程(或JAVA术语中的方法(method))。其他语言使用不同的术语。
当步骤162中检测到初始化例程时,在步骤163中,典型地通过将进一步的指令***到例程中来对其进行修改。可替换地,可在例程前***修改指令。一旦完成了修改步骤163,则如步骤164所示,继续加载过程。
图17示出了修改的特定形式。在开始步骤171中的例程之后,在步骤172中,给待初始化的结构、资产或资源(在JAVA中称作类或对象)分配名称或标签,这些名称或标签可以被所有机器在全局中使用。这是通过图15的服务器机器X所维护的表来最方便地完成的。该表还包括待初始化的类或对象的状态。
如图17所示,如果步骤173和174确定全局名称还未在其他地方(即执行加载的机器以外的机器)初始化,则这意味着:由于这是要创建的第一个这种对象或类,因此可通过执行步骤176来以正常方式初始化所述对象或类。
但是,如果步骤173和174确定所述全局名称已经在其他地方初始化了,则这意味着另一机器已经初始化了该类或对象。因此,通过执行步骤175,常规初始化例程被完全中止。
图18示出了加载机器(M1、M2...Mn之一)向图15的服务器机器X所作的问询。如步骤181所示,加载机器的操作被暂时中断,直到收到来自机器X的回复,如步骤182所示。
图19示出了图15的服务器机器X响应于图18步骤181的这种问询而进行的活动。在步骤192和193中确定初始化状态,如果已经初始化,则通过执行步骤194来将具有该意思的响应发送到问询的机器。同样,如果初始化状态是未初始化,则通过执行步骤195和196来发送对应的回复。然后,通过步骤182来创建的等待的问询的机器能够相应地作出响应。
参考附件,其中:
附件A1-A10示出与字段相关的实际代码,
附件B1是来自未修改的<clinit>指令的典型代码片段,
附件B2是关于修改的<clinit>指令的等效,
附件B3是来自未修改的<init>指令的典型代码片段,
附件B4是关于修改的<init>指令的等效,
此外,附件B5是附件B2的代码的替代,以及
附件B6是附件B4的代码的替代。
另外,附件B7是InitClient的源代码,其向“初始化服务器(initializationserver)”查询有关类或对象的初始化状态。
附件B8是InitServer的源代码,其接收InitClient的初始化状态查询,并作出响应将对应的状态返回。
相似地,附件B9是附件B1-B6的实例之前/之后所使用的示例应用的源代码。
现在转向图20,示出了修改与类相关的<clinit>例程以便从附件B1的代码片段转换成附件B2的代码片段的所遵循的过程。在步骤201开始将应用程序50初始加载到JAVA虚拟机72上,通过执行步骤202,仔细检查每行代码,以便检测那些代表<clinit>例程的指令。一旦检测到,通过执行步骤203,如附件B2中所示对<clinit>例程进行修改。如步骤204所示,修改完成后,继续加载过程。
附件B1和B2分别是摘录<clinit>指令之前和之后。添加到该方法(method)中的修改的代码以粗体突出显示。在附件B1的原始代码样本中,<clinit>方法创建其自己的新对象,并将其写入称作“thisTest”的存储器位置(字段)。因此,在没有分布式环境中的类加载管理的情况下,每个机器将以不同对象来重新初始化同样的共享存储器位置(字段)。显然这不是正加载的应用程序的程序员所期望发生的。
因此,利用DRT,通过改变<clinit>方法,在应用代码加载到机器中时对其进行修改。所作的改变(以粗体突出显示)是<clinit>方法执行的初始指令。通过调用isAlreadyLoaded()方法,所添加的这些指令检查该类是否已经加载,isAlreadyLoaded()方法返回与该类的加载状态对应的真或假。
DRT的该isAlreadyLoaded()方法可以任选地采用代表该类的唯一标识符的自变量(见附件B5和B6),例如在确定该类的加载状态时将使用的类的名称、或代表该类的类对象、或在所有机器上表示该类的唯一号码。这样,通过使用每个类的唯一标识符来咨询isAlreadyLoaded表中的正确记录,DRT可同时支持多个类的加载,而不会混淆多个类中哪些已加载,哪些未加载。
DRT可以多种方式来确定类的加载状态。优选地,如果该类已加载,DRT可依次问询每个机器是否该类已被加载,而如果有任何机器回复真,则返回真,否则返回假。可替换地,本地机器上的DRT可咨询共享的记录表(也许在单独的机器上(如机器X),或咨询本地机器上的一致的共享记录表,或数据库)来确定该类是否已经加载。
如果DRT返回假,则这意味着该类以前还未加载到分布式环境中的任何机器上,因此,该执行将视为第一次和原始的。结果,DRT必须将共享记录表中该类的“isAlreadyLoaded”记录更新为真,这样,现在在所有其他机器上,包括当前机器上,isAlreadyLoaded的所有随后的引用均将返回真。因此,如果DRT.isAlreadyLoaded()返回假,则修改的<clinit>方法继续执行原始代码块,其现在跟在被***的三个指令之后。
另一方面,如果DRT返回真,则这意味着该类已经加载于分布式环境中,如被加载的类的共享记录表中所记载的那样。在这种情况下,由于其将覆写已经初始化的存储器位置等,因此不执行原始代码块。因而,当DRT返回真时,所***的三个指令防止执行原始代码,并直接返回应用程序。
图21示出了与对象有关的<init>例程的等效过程,其中步骤212和213相当于图20中的步骤202和203。这导致附件B3的代码被转换成附件B4的代码。
针对<clinit>的相似修改也用于<init>。如步骤212所示检测应用程序的<init>块(或多个<init>块,因为可以存在多个,这与<clinit>不同),并如步骤213所示对其进行修改,以便在分布式环境上一致地运转。
在附件B3的示例中,应用程序的<init>指令利用加载时间的时间戳来初始化存储器位置(字段)。例如,应用可用此来记录该对象是何时创建的。显然,在对等对象可在不同时间加载的分布式环境中,需要特殊的处理,以保证首先加载的对等对象的时间戳不被后来的对等对象所覆写。
修改发生后的被分解的指令序列示于附件B4中,而且所修改/***的指令以粗体突出显示。对于<init>修改,与<clinit>修改不同的是,通常要求将修改指令置于“invokespecial”指令之后,而不是在刚开始的位置。这样作的原因是JAVA虚拟机规范所要求的。其他语言经常具有相似的细微的设计差别。
测试的基本概念是初始化是否已经执行,如果没有,则进行,如果已经执行,则不再执行进一步的初始化;存在几种可以执行这个概念的不同方式。
在第一实施例中,特定机器如机器M2将类或对象加载于其自身上,然后(按顺序或同时地)加载其他机器M1、M3...Mn的每一个。在该可称作“主/从”的设置中,机器M1、M3...Mn的每一个加载机器M2所给予的内容。
在该“主/从”设置的一种变型中,机器M2将未修改形式的<clinit>例程加载到机器M2上,然后通过整个删除初始化例程来修改该类,并将修改后的类加载到其他机器上。这样,在该实例中,修改不是绕过初始化例程,而是将其从除一个机器以外的所有机器上删除。
在又一实施例中,每个机器接收初始化例程,但对其进行修改,并将修改后的例程加载于该机器上。这使得每个机器执行的修改能够有些许不同,基于其架构和操作***来优化,但是仍然与所有其他相似的修改一致。
在又一设置中,特定机器如M1加载类,而所有其他机器M2、M3...Mn进行修改以删除初始化例程并加载修改后的版本。
在所有实例中,供给可以有分支(即M2直接供给M1、M3、M4等的每个)或可以是级联或按顺序的(即M2供给M1,然后M1供给M3,M3再供给M4,依此类推)。
在又一设置中,初始机器如M2可执行初始加载,然后产生列出机器M2所加载的所有类的表。该表然后(以分支或级联的方式)被发送给所有其他机器。然后,如果除了M2以外的一个机器需要访问所述表中列出的类,则其发送请求给M2,以提供必要的信息。因此,提供给机器Mn的信息通常不同于加载到机器M2中的初始状态。
在上述情况下,有必要使表中每个条目附带一个计数器,该计数器在每次加载类时增加。因而,当需要数据时,响应于该需求来传送类内容和对应计数器的计数二者。这种“按要求的(on demand)”模式增加了每个计算机的开销,但减少了互连计算机的通信网络上的流量。
在又一设置中,机器M1...Mn可将所有加载请求发送给(图15的)附加机器X,该附加机器X通过上述方法中的任一种来执行修改,并将修改后的类返回给机器M1...Mn的每个,机器M1...Mn的每个然后在本地加载该类。在这种设置中,机器M1...Mn不维护任何类的记录表,相反,它们将所有加载请求转发到机器X,机器X维护加载类的表,并根据给定类是否是第一次加载到机器M1...Mn上,将修改后的类返回给每个机器。机器X进行的修改可包括本发明的范围覆盖的任何修改。
再参考图14,在JAVA语言中,初始化例程<clinit>仅在加载给定类文件50A时发生一次。但是初始化例程<init>经常发生,例如,每次创建新对象50X、50Y和50Z时都发生。此外,类是在对象之前加载的,这样,在图14所示的具有单个类50A和三个对象50X-50Z的应用程序中,首先加载第一类50A,然后加载第一对象50X,然后加载第二对象50Y,最后加载第三对象50Z。这里,如图14中所示,仅有单个计算机或机器72,而因为图14的单个机器能够容易地跟踪特定对象50X-50Z将来是否倾向于被需要用于程序50,因此,旨在加载过程期间工作的初始化例程的运行中没有出现冲突或不一致。这是通过维护“handle count”等来完成的。该计数跟踪可执行代码中对特定对象进行引用之处的数量。当特定对象的handle count达到0时,在可执行代码中没有对该对象进行引用之处。这于是该对象被称作“可终结化”。
一旦达到该状态,由于不再需要,因此可安全地删除(或清理或终结化)该对象。相同的过程将必要的修正(mutatis mutandis)施加于类。特别是,计算机程序员在使用JAVA语言和架构来编写程序时,不需要为该清理、删除和终结化编写任何具体代码。相反,单个JAVA虚拟机72可跟踪类和对象的handle count,并以不引人注意的方式在需要时进行清理(或进行终结化)。
但是,在图8(还有图31-33)中所示的设置中,提供了多个单独的计算机或机器M1、M2...Mn,其每个经由通信网络53来互连,且其每个被提供有修改器51(如图5中所示,并通过图8中的DRT 71实现)并加载有公共应用程序50。实质上,修改器51或DRT 71修改应用代码50,以在多个单独的机器M1、M2...Mn上执行清理例程。因此随之而来的是,使得在这种计算环境中,有必要保证各机器的每个以(关于彼此)一致的方式来终结化。
特别地,尽管一个特定机器(如M3)可不再调用一对象或类,但另一机器(如M5)在将来可仍然需要引用该对象和类。因此,如果要从机器M3上删除该对象或类,那么如果M5要写入该对象或修改其值,则由于M3在其本地存储器中没有包括该相关的对象,因此该值的改变就不会传播到所有机器M1、M2...Mn。另外,如果机器M3要执行对给定对象或类的清理例程,清理例程将不仅针对该机器上的该对象进行清理,而是针对所有其他机器上的对等对象。因而,使得机器M5上的该对象无效。这样,就不会实现同一应用程序的同时运行所要求的、机器M1、M2...Mn的每个的基本相同的存储器内容的目标。
为了保证一致的终结化或清理,应用程序50被仔细检查,以便检测定义清理例程的程序步骤。该仔细检查可在加载前、或加载过程期间、或甚至在加载过程之后(但在应用代码50的相关对应部分的执行之前)发生。编译过程可这样理解:即术语编译通常涉及代码或语言上的改变,如从源代码到目标代码或从一种语言到另一种。但是,在本实例中,术语“编译”(及其语法上的等效)并不受限于此,而可包括包含同一代码或语言中的修改。
结果,在上述仔细检查中,初始地查找清理例程,当找到时,***修改代码,以便引起修改后的清理例程的发生。该修改后的例程要在任何特定机器上中止该清理例程,除非所有其他机器均将该待删除的对象或类标记为删除。存在可执行这种修改和加载的几种不同的模式。在这点上,参考附件C,其中阐述了各种清理或终结化的示例。
因此,在一种模式中,加载机器(在本例中是JVM#1)上的DRT 71/1询问所有其他机器的DRT 71/2...71/n例如是否任何其他机器M2...Mn利用了(即没有标记为删除)第一类50A。如果对该问题的回答为肯定,则针对机器JVM#1上的第一对象50X来关断或禁止正常的清理过程。如果回答为否(即第一对象50X在所有其他机器M2...Mn上标记为删除),则进行正常的清理过程,而且不仅从机器JVM#1上而且从所有其他机器M2...Mn上删除第一对象50X。优选地,该清理任务分配给将对象或类标记为删除的最后的机器M1。
图22示出了关于终结化所遵循的优选通用过程。在开始加载161A之后,待执行的指令按顺序来考虑,并且如在步骤162A中所示地检测所有清理例程。在JAVA语言中,这些是“finalize()”例程(或JAVA术语中的方法)。其他语言使用不同的术语。
当检测到初清理例程时,在步骤163A中,典型地通过将进一步的指令***到例程中来对其进行修改。可替换地,可在例程之前***修改指令。一旦完成了修改,则如步骤164A所示,继续加载过程。
图23示出了修改的一种特殊形式。首先,如步骤172A中所示,可能是被清理的候选的结构、资产或资源(在JAVA中称作类或对象)50A、50X...50Y,已经被分配了名称或标签,所述名称或标签可由所有机器M1、M2...Mn在全局使用。这优选地发生于对类或对象进行原始初始化时。这是通过服务器机器X所维护的表来最方便地完成的。该表还包括类或对象的“clean up status(清理状态)”。在该优选实施例中,该表还包括存储已经将该资产标记为删除的机器数量的计数的计数器。因此,小于(n-1)的总计数值表示作为网络整体针对该资产的“do not clean up(不清理)”状态。
如图23所示,如果全局名称未在所有其他机器(即除了提请执行清理例程的机器以外)上标记为删除,则如步骤174A所示,这意味着:由于仍然需要该对象或类,应该中止所提请的对该对象或类的清理例程。
如果全局名称在所有其他机器上标记为删除,则这意味着其他机器不再需要该类或对象。结果可以,并且应该执行步骤176A所示的正常清理例程。
图24示出提请执行清理例程的机器(M1、M2...Mn之一)向服务器机器X所作的问询。如步骤181A和182A所示,该提请的机器的操作被临时中断,直到收到来自机器X的回复,如步骤182A所示。
图25示出了机器X响应于这种问询而进行的活动。如步骤192A所示确定清理状态,如果否-指定的资源在(n-1)个机器上未被标记为删除(即在其他地方使用),则带有那个意思的响应被发送到问询的机器194A,而“marked for deletion(标记为删除)”计数器增一(1),如步骤197A所示。相似地,如果回答为肯定-如步骤195A所示的那样发送对应的回复。等待问询的机器182A然后能够相应地作出响应。如图25中虚线所示,优选地,除了步骤195A中所示的肯定响应之外,还对共享的表进行更新,这样,全局命名的资产的状态变成“清理”,如步骤196A所示。
再参考图14,当通过程序员使用同步例程来规定时,图14的单个机器能够容易地执行特定对象50X-50Z的同步。由于每个对象仅在本地存在,图14的单个JAVA虚拟机能够保证对象如程序员规定的那样被正确同步,因此在任何单个时间点仅为可执行代码的一部分来使用。如果另一部分可执行代码希望使用相同的对象,则可能的竞争由JAVA虚拟机这样来解决,也即应用程序的其他执行部分只好等待直到第一部分完成。
同一过程对类50A施加必要的修正。特别是,当使用JAVA语言和架构来编写程序时,计算机程序员仅需使用同步例程,以便提供该竞争避免。这样,单个JAVA虚拟机可跟踪多个类和对象的使用,并以不引人注意的方式在需要时避免任何对应的问题。仅一个对象或类被独占地使用的过程称作“同步”。在JAVA语言中,指令“monitorenter”和“monitorexit”表示同步例程的开始和结束,其分别导致对“lock”的获取和释放,所述“lock”防止资产为竞争的主题。
但是,在图8(还有图31-33)中所示的设置中,提供了多个单独的计算机或机器M1、M2...Mn,其每个经由通信网络53来互连,且其每个被提供有修改器51(如图5中所示,并通过图8中的DRT 71实现)并加载有公共应用程序50。实质上,修改器51或DRT 71保证:当在一个机器上运行的应用程序50的部分(例如利用同步)独占地使用特定本地资产(如对象50X-50Z或类50A)时,其他机器M2...Mn不在其本地存储器中使用对应的资产。
特别地,尽管一个特定机器(如M3)独占地使用一对象或类,但另一机器(如M5)也有可能被其执行的代码指示来在该时独占使用该对象和类。因此,如果该对象或类要被二者独占使用,那么该对象和应用作为一个整体的行为没有定义-也就是说,在对象的正确独占使用没有被程序员明确规定的情况下,可能会导致机器M5和机器M3之间的永久不一致。这样,就不会实现同一应用程序的同时运行所要求的、每个机器M1、M2...Mn的基本相同的存储器内容的目标。
为了保证一致的同步,应用程序50被仔细检查,以便检测定义同步例程的程序步骤。该仔细检查可在加载前、或加载过程期间、或甚至在加载过程之后(但在相关对应的应用代码执行之前)发生。编译过程可这样理解:即术语编译通常涉及代码或语言上的改变,如从源到目标代码或从一种语言到另一种。但是,在本实例中,术语“编译”(及其语法上的等效)并不受限于此,而可包括包含同一代码或语言中的修改。
参考附件D,其中:
附件D1是来自未修改的同步例程的典型代码片段,以及
附件D2是关于所修改的同步例程的等效,
附件D1和D2分别在同步例程的摘录之前和之后。添加到该方法的修改代码以粗体突出显示。在附件D1的原始代码样本中,代码在同步声明内增加共享存储器位置(计数器)。同步声明的目的是为了保证多线程应用中的增量操作的线程安全性。因此,在分布式环境中没有同步管理的情况下,每个机器将在隔离中执行同步,由此有可能同时增加共享的计数器,导致潜在的竞态条件和不一致的存储器。显然这不是应用程序的程序员所期望发生的。
因此,利用DRT,通过改变同步例程,在应用代码加载到机器中时被进行修改。所作的修改(以粗体突出显示)是同步例程所执行的初始指令和结束指令。这些添加的指令用于在分布式环境中的所有其他机器上附加地执行同步,由此保持多个机器上应用程序的同步行为。
DRT的acquireLock()方法利用表示该对象的唯一标识符的自变量(见附件D2),例如对象名称、正在考虑的对象的引用或在所有节点上表示该对象的唯一号码,以在获得规定对象的全局锁定中使用。这样,通过使用每个对象的唯一标识符来咨询共享同步表中的正确记录,DRT可同时支持多个对象的同步,而不会混淆多个对象的哪个已经同步哪个还没有同步。
DRT可以多种方式来确定对象的同步状态。优选地,其可依次问询每个机器其对该对象的本地拷贝当前是否同步,而如果有任何机器回复真,则等待直到该对象不同步,否则在本地对该对象进行同步。可替换地,本地机器上的DRT可咨询共享的记录表(也许在单独的机器上(如机器X),或本地机器上一致的共享记录表,或数据库)来确定该对象是否已经由任何其他机器标记为同步,如果是这样,则等待直到该对象的状态变为“不同步”,然后通过将该对象标记为同步来获得锁定,否则通过由该机器将该对象标记为同步来获得锁定。
如果DRT确定当前没有其他机器具有对该对象的锁定(即没有其他机器已经将该对象同步),则例如通过修改同步状态共享表中的对应条目,或可替换地,通过顺序获得除当前机器以外的所有其他机器上的锁定,在所有其他机器上获得对该对象的锁定。只有当该机器成功确认当前没有其他机器已对该对象同步、并且该机器已在本地对应同步时,原始同步代码块才开始执行。
另一方面,如果DRT确定另一机器已经对该对象进行了同步,那么该机器将推迟执行原始同步代码块,直到DRT可确认没有其他机器当前正在执行针对该对象的同步声明而且该机器已经在本地对该对象进行了对应的同步。在这种情况下,将不执行原始代码块,直到该机器可确保没有其他机器正在执行针对该对象的同步声明,原因是,由于竞态条件、存储器不一致将可能引起在参与的机器上损坏该对象,而这同样是同步声明的并发执行所导致的。因此,当DRT确定了该对象当前“已同步”时,DRT通过暂停“acquireLock()”操作的执行来防止原始代码块的执行,直到当前锁定的拥有者执行了对应的“releaseLock()”操作为止。
因此,在执行“releaseLock()”操作时,例如通过在同步状态共享表中将该对象标记为“未同步”,或可替换地通过按顺序释放在所有其他机器上获得的锁定,当前“拥有”锁定(即正在执行同步声明)的机器指示其同步声明的结束。在这点,然后,等待开始执行对应的同步声明的任何其他机器可通过继续执行其被推迟(即延迟)的“acquireLock()”操作,例如,在同步状态共享表中将自身标记为执行针对该对象的同步声明,或可替换地在每个其他机器上按顺序获得本地锁定,来要求对该对象的锁定的拥有。
这样,利用DRT,通过改变同步例程(包含开始“monitorenter”和结束“monitorexti”指令),在应用代码加载入机器中时对其进行了修改。所作的修改(以粗体突出显示)是同步例程执行的初始指令。这些添加的指令检查该锁定是否已被另一机器获得。如果该锁定尚未被另一机器获得,则该机器的DRT通知所有其他机器该机器已获得锁定,由此停止其他机器执行针对该锁定的同步例程。
DRT可以多种方式来记录机器的锁定状态,例如:
1.对应于同步例程的入口,DRT单独咨询每个机器以确定是否已获得该锁定。如果是,则DRT暂停同步例程的执行,直到所有其他机器不再拥有对该资产或对象的锁定。否则,DRT执行该同步例程。可替换地,
2.对应于同步例程的入口,DRT咨询记录的共享表(如共享数据库,或每个参与的机器上的共享表的拷贝),该共享表指示是否有任何机器当前“拥有”该锁定。如果是,则DRT暂停在该机器上执行同步例程,直到所有其他机器不再拥有对该对象的锁定。否则,DRT将该机器记录在共享表中(或者多个共享表中,如果例如在多个机器上存在多个记录表)作为该锁定的拥有者,然后执行同步例程。
相似地,当锁定被释放时,换言之,当同步例程的执行结束时,DRT能以很多可替换的方式将机器的锁定状态“去掉记录(un-record)”,例如:
1.对应于同步例程的出口,DRT单独通知每个其他机器其不再拥有锁定。可替换地,
2.对应于同步例程的出口,DRT更新记录共享表中该被锁定的资产或对象的记录,这样该机器不再被记录成拥有该锁定。
另外,DRT能以多种可替换的方式将需要获得锁定对象的机器排队,例如:
1.对应于同步例程的入口,DRT通知锁定对象的当前拥有者,特定机器欲在当前拥有的机器释放时获得该锁定。如果没有其他等待的机器,则该特定机器将该特定机器的兴趣存储在表中,在该锁定对象的同步例程结束的随后,其通知等待的机器其可获得该锁定对象,因而开始执行其同步例程。
2.对应于同步例程的入口,DRT通知该锁定对象的当前拥有者:特定机器(如M6)将在该机器(如M4)释放时获取锁定。如果该机器M4在咨询其等待该锁定对象的机器记录后发现已经有一个或多个机器在等待,则将机器M6附于想要获取该锁定对象的机器列表的末尾,或可替换地,将来自M6的请求转发给第一个等待的机器或任何其他等待的机器,所述第一个等待的机器或任何其他等待的机器又将机器M6记录在它们的记录表中。
3.对应于同步例程的入口,DRT将自身记录在记录共享表中(例如,存储在可由所有机器访问的共享数据库中的表、或基本上相似的多个单独的表)。
另外,对应于同步例程的出口,DRT可通知其他排队的机器由该机器以下列可替换的方式来获取该锁定,例如:
1.对应于同步例程的出口,DRT通知正在等待的机器之一(例如,正在等待的机器队列中的该第一个机器)该锁定已释放,
2.对应于同步例程的出口,DRT通知正在等待的机器之一(例如,正在等待的机器队列中的该第一个机器)该锁定已释放,此外,提供整个机器队列的拷贝(例如,等待该锁定的第二个机器和随后的机器)。这样,第二个机器从第一个机器继承正在等待的机器的列表,并由此在列表中每个机器依次获得并随后释放该锁定时,保证正在等待的机器队列的连续性。
在上述仔细检查期间,初始地查找“monitor enter”和“monitor exit”指令(或方法),并且当找到时,***修改的代码,以得到修改后的同步例程。该修改后的同步例程获取并释放锁定。.执行这种修改和加载的有几种不同的模式。附件D提供了进一步的信息。
图26示出了关于同步的所要遵循的优选一般过程。在开始加载161B后,如步骤162B所示,按顺序考虑待执行的指令,并检测所有的同步例程。在JAVA语言中,这些是“monitor enter”和“monitor exit”指令。其他语言使用不同的术语。
在检测到同步例程之处,典型地通过将进一步的指令***例程中对其进行修改。可替换地,修改的指令可***在例程前。一旦完成修改,则继续加载过程。如步骤163B所示,所述修改优选地采用“acquire lock on allother machines(在所有机器上获取锁定)”操作和“release lock on all othermachines(在所有机器上释放锁定)”修改的形式。
图27示出了修改的特定形式。首先,如步骤172B所示,待同步的结构、资产或资源(在JAVA中称作类或对象,如50A、50X-50Y)已被分配名称或标签,所述名称或标签可由所有机器在全局使用。这优选地在初始地对类或对象进行初始化时发生。这通过服务器机器X所维持的表十分方便地完成。该表还包括类或对象的同步状态。在优选实施例中,该表还包括存储已请求使用该资产的机器标识的队列设置。
如图27的步骤173B所示,接下来,“acquire lock”请求被发送到机器X,之后,如步骤174B中所示,发送机器等待对锁定获取的确认。因此,如果全局名称已经被锁定(即对应资产正在被另一机器而不是提请获取该锁定的机器所使用),则这意味着所提请的对象或类的同步例程应该暂停,直到该对象或类被当前拥有者解锁。
可替换地,如果全局名称未被锁定,则这意味着没有其他机器正在使用该类或对象,而且立即接收到对锁定获取的确认。在收到对锁定获取的确认后,如步骤175B所示,允许继续执行同步例程。
图28示出了想要放弃锁定的应用程序执行机器所遵循的过程。步骤181B指示了初始步骤。该提请的机器的操作由步骤183B、步骤184B临时中断,直到对应于步骤184B,收到来自机器X的回复,然后如步骤185B所示继续执行。任选地,且如步骤182B所示,使请求释放锁定的机器在向机器X作出请求之前查询该锁定的“global name(全局名称)”。这样,可获取并释放多个机器上的多个锁定,而不会彼此干扰。
图29示出了机器X响应于(图27的)“acquire lock”问询而进行的活动。当在步骤191B接收到“acquire lock”请求后,在步骤192B和193B确定锁定状态,如果否-所指定的资源不空闲,在步骤194B将问询的机器的标识添加到等待获取请求的队列(或以问询的机器的标识来形成等待获取请求的队列)。可替换地,如果回答是肯定的-所指定的资源空闲-则在步骤197B发送对应的回复。然后,等待的问询的机器能够通过执行图27的步骤175B来相应地执行同步例程。除了肯定响应以外,还在步骤196B更新共享表,以使全局命名的资产的状态改变成“locked(锁定)”。
图30示出了机器X响应于图28的“release lock”请求而进行的活动。当在步骤201接收到“release lock”请求后,如步骤202所示,机器X可选地并优选地确认所述请求释放锁定的机器正是该锁定的当前拥有者。接下来,在步骤203确定队列状态,如果没有机器正在等待获取该锁定,则如步骤207所示,机器X在共享表中将该锁定标记为“unowned(未被拥有)”,并如步骤208所示,可选地将对释放的确认发送回请求的机器。这使请求的机器能够执行图28的步骤185B。
可替换地,如果肯定-即有其他机器正在等待获取该锁定-则如步骤204所示,机器X将该锁定标记为现在由队列中的下一机器获取,然后在步骤205将对锁定获取的确认发送到该排队的机器,并因此如步骤206所示,将新锁定拥有者从等待机器的队列中去除。
现在转到图31-33,其中示出了两个膝上计算机101和102。计算机101和102不必是相同的,并且实际上,一个可以是IBM或IBM-克隆,而另一个可以是Apple计算机。计算机101和102具有:两个屏幕105、115,两个键盘106、116,但只有单个鼠标107。两个机器101、102借助于单个同轴线缆或双绞线线缆314来互连。
两个简单的应用程序被下载到机器101、102的每个上,如上所述,所述程序在其被加载时得到修改。在该实施例中,第一应用是简单的计算器程序,并导致计算器108的图像显示在屏幕105上。第二程序是图形程序,其显示在矩形框310内随机移动的4个不同颜色的彩色块109。同样,在加载后,框310显示在屏幕105上。每个应用独立运行,这样块109在屏幕105上随机运动,而同时可选择(利用鼠标107)计算器108内的数字连同数学运算符(如加法或乘法),使得计算器108显示结果。
鼠标107可用来“抓取”框310,并将其移动到右边跨过屏幕105到屏幕115上,以达到图32中所示的情形。在该设置中,计算器应用在机器101上执行,而引起框310的显示的图形应用在机器102上执行。
但是,如图33所示,可以借助于鼠标来将计算器108拖到右边,如图32中所示,以便使计算器108的一部分分别由屏幕105、115来显示。相似地,可借助于鼠标107将框310拖到左边,如图32中所示,以使框310部分显示在屏幕105、115的每个上,如图33中所示。在该配置中,部分计算器操作在机器101上执行,而部分在机器102上执行,同时部分图形应用在机器101上进行,而剩余的在机器102上进行。
上文仅描述了本发明的某些实施例,而对本领域普通技术人员显而易见的是,可在不背离本发明范围的情况下对其进行修改。例如,对JAVA的引用可包括JAVA语言,还可包括JAVA平台和架构。
编程领域的普通技术人员将意识到,当附加代码或指令***现有代码或指令集中以对其进行修改时,现有代码或指令集会需要进一步的修改(如通过对顺序的指令重新编号),以便满足偏移、分支、属性和标记等。
相似地,在JAVA语言中,存储器位置包括例如字段和数组类型二者。以上描述讨论了字段,而数组类型所需的改变基本上也是同样必要的修正。本发明还可同等地应用于与JAVA相似的(包括:过程式、宣告式和面向对象的)编程语言,包括Micrsoft.NET平台和架构(Visual Basic、VisualC/C++和C#)FORTRAN、C/C++、COBOL、BASIC等
其中修改了JAVA初始化例程代码的上述实施例基于这样的假设:即每个机器M1...Mn的运行时间***(即以C和JAVA编写的JAVAHOTSPOT VIRTUAL MACHINE)或操作***(例如以C和汇编语言编写的LINUX)将调用JAVA初始化例程。可以不修改JAVA初始化例程,而是对调用JAVA初始化例程的LINUX或HOTSPOT例程进行修改,这样,如果已经加载了对象和类,则不调用JAVA初始化例程。为了包含这样的设置,术语“初始化例程”应理解为在其范围内包括JAVA初始化例程以及JAVA初始化例程和调用或发起JAVA初始化例程的LINUX或HOTSPOT代码片段的“组合”二者。
其中修改了JAVA终结化或清理例程代码的上述实施例基于这样的假设:即每个机器M1、M2...Mn的运行时间***(即以C和JAVA编写的JAVA HOTSPOT VIRTUAL MACHINE)或操作***(例如以C和汇编语言编写的LINUX)将调用JAVA终结化例程。可以不修改JAVA终结化例程,而是对调用JAVA终结化例程的LINUX或HOTSPOT例程进行修改,这样,如果不要删除对象和类,则不调用JAVA终结化例程。为了包含这样的设置,术语“终结化例程”应理解为在其范围内包括JAVA终结化例程以及JAVA终结化例程和调用或发起JAVA终结化例程的LINUX或HOTSPOT代码片段的“组合”二者。
其中修改了JAVA同步例程代码的上述实施例基于这样的假设:即每个机器M1、M2...Mn的运行时间***(即以C和JAVA编写的JAVAHOTSPOT VIRTUAL MACHINE)或操作***(例如以C和汇编语言编写的LINUX)将在本地机器(如M2)而不是在任何其他机器(M1、M3...Mn)上正常获取锁定。可以不修改JAVA同步例程,而是对在本地获取锁定的LINUX或HOTSPOT例程进行修改,这样,其对应地在所有其他机器上获得锁定。为了包含这样的设置,术语“同步例程”应理解为在其范围内包括JAVA同步例程以及JAVA同步例程和执行锁定获取和释放的LINUX或HOTSPOT代码片段的“组合”二者。
在此使用的术语对象和类是从JAVA环境中导出的,且旨在包含从不同环境如动态链接库(DLL)或目标代码包或功能单元或存储器位置导出的相似术语。
在此所用的术语“包括”(及其语法上的变型)是“具有”或“包含”的包含性的意义,而不是“仅由......来构成”的“排他性”的意义。
版权须知
该专利说明书包含受版权保护的材料。版权的所有者(即申请人)不反对为了评论的目的从公众可获得的相关专利局文件中复制该专利说明书或相关材料,但是保留所有的版权。特别是,在没有版权所有者的特别书面许可的情况下,不得将各指令输入计算机中。
附件A
下面是JAVA语言的程序列表:
A1.该第一摘录是修改代码的部分。其在整个代码阵列中搜索,并且在找到putstatic指令(opcode 178)时,其实施所述修改。
//START
byte[]code=Code_attribute.code; //Bytecode of a given method in a
//given classfile.
int code_length =Code_attribute.code_length;
int DRT=99; //Location ofthe CONSTANT Methodref_info for the
//DRT.alert()method.
for(int i=0;i<code_length;i++){
if((code[i]&0xff)==179){//Putstatic instruction.
System.arraycopy(code,i+3,code,i+6,code_length-(i+3));
code[i+3]=(byte)184; //Invokestatic instruction forthe
//DRT.alert()method.
code[i+4]=(byte)((DRT>>>8)&0xff);
code[i+5]=(byte)(DRT&0xff);
}
}
//END
A2.该第二摘录是DRT.alert()方法的部分。这是DRT.alert()方法被调用时的主体。
//START
public static void alert(){
synchronized {ALERT_LOCK){
ALERT LOCK.notify();//Alerts a waiting DRT thread in the background.
}
}
//END
A3.该第三摘录是DRT Sending的部分。该代码片段示出了DRT在得到通知后在单独线程中跨网络地发送值。
//START
MulticastSocket ms=DRT.getMulticastSocket (); //The multicast socket
//used by the DRT for
//communication.
byte nameTag=33; //This is the″name tag″on the network for this]
//field.
Field field=modifiedClass.getDeclaredField(″myField1″); //Stores
//the field
//from the
//modified
//class.
//In this example,the field is a byte field.
while(DRT.isRunning()){
synchronized (ALERT_LOCK){
ALERT_LOCK.wait(); //The DRT thread is waiting for the alert
//method to be called.
byte[]b=new byte[]{nameTag,field.getByte(null)}; //Stores
//the
//nameTag
//and the
//value
//of the
//field from
//the modified
//class in a
//buffer.
DatagramPacket dp=new DatagramPacket(b,0,b.length);
ms.send(dp);//Send the buffer out across the network.
}
}
//END
A4.第四摘录是DRT receiving的部分。这是接收DRT在网络上发送的告警的代码片段。
//START
MulticastSocket ms =DRT.getMulticastSocket();//The multicast socket
//used by the DRT for
//comunication.
DatagramPacket dp=new DatagramPacket(new byte[2],0,2);
byte nameTag=33; //This is the″name tag″on the network for this
//field.
Field field=modifiedClass.getDeclaredField(″myField1″);//Stores the
//field from
//the modified
//class.
//In this example,the field is a byte field.
while(DRT.isRunning){
ms.receive(dp);//Receive the previously sent buffer from the network.
byte[]b=dp.getData();
if(b[0]==nameTag){//Check the nametags match.
field.setByte(null,b[1]);//Write the value from the network packet
//intothe field location in memory.
A5.第五摘录是发生修改前的示例应用。
Method void setValues(int,int)
0 iload_1
1 putstatic#3<Field int staticValue>
4 aload_0
5 iload_2
6 putfield#2<Field int instanceValue>
9 return
A6.第六摘录是与5中相同的示例应用已经执行修改后的情形。修改以粗体突出显示。
Method void setValues(int,int)
0 iload_1
1 putstatic#3<Field int staticValue>
4 ldc#4<String″example″>
6 iconst_0
7 invokestatic#5<Method void alert(java.lang.Object,int)>
10 aload_0
11 iload_2
12 putfield#2<Field int instanceValue>
15 aload_0
16 iconst_1
17 invokestatic#5<Method void alert(java.lang.Object,int)>
20 return
A7.第七摘录是摘录5和6中所用的示例应用的源代码。
import java.lang.*;
public class example{
/**Shared static field.*/
public static int staticValue=0;,
/**Shared instance field.*/
public int instanceValue=0;
/**Example methodthatwrites to memory (instance field).*/
public void setValues(int a,int b){
staticValue=a;
instanceValue=b;
}
}
A8.第八摘录是FieldAlert的源代码,其告警“distrubuted runtime”以传播改变的值。
import j ava.lang.*;
import java.util.*;
import java.net.*;
import java.io.*;
public class FieldAlert{
/**Table of alerts.*/
public final static Hashtable alerts=new Hashtable ();
/**Object handle.*/
public Obj ect reference=null;
/**Table of field alerts for this object.*/
public boolean[]fieldAlerts=null;
/**Constructor.*/
public FieldAlert(Object o,int initialFieldCount){
reference=o;
fieldAlerts=new boolean[initialFieldCount];
}
/**Called when an application modifies a value.(Both objects and
classes)*/
public static void alert(Obj ecto,int fieldID){
//Lock the alerts table.
synchronized (alerts){
FieldAlert alert=(FieldAlert)alerts.get(o);
if(alert==null){ //This object hasn′tbeen alerted already,
//so add to alerts table.
alert=new FieldAlert(o,fieldID+1);
alerts.put(o,alert);
}
if(fieldID>=alert.fieldAlerts.length){
//Ok,enlarge fieldAlerts array.
boolean[]b=new boolean[fieldID+1];
System.arraycopy (alert.fieldAlerts,0,b,0,
alert.fieldAlerts.length);
alert.fieldAlerts=b;
}
//Recordthe alert.
alert.fieldAlerts[fieldID]=true;
//Mark as pending.
FieldSend.pending=true; //Signal that there is one or more
//propagations waiting.
//Finally,notifythe waiting FieldSend thread(s)
if(FieldSend.waiting){
FieldSend.waiting=false ;
alerts.notify();
}
}
}
}
A9.第九摘录是FieldSend的源代码,其将通过FieldAlert告警给其的改变的值传播。
import java.lang.*;
import java.lang.reflect.*;
import java.util.*;
import java.net.*;
import java.io.*;
public class FieldSend implements Runnable{
/**Protocol specific values.*/
public final static int CLOSE=-1;
public final static int NACK=0;
public final static intACK=1;
public final static int PROPAGATE OBJECT=10;
public final static int PROPAGATE CLASS=20;
/**FieldAlertnetwork values.*/
public final static String group=
System.getProperty(″FieldAlert_netwotk_group″);
public final static int port=
Integer.parseInt(System.getProperty(″FieldAlert_network_port″));
/**Table of globalID′s for local objects.(hashcode-to-globalID
mappings)*/
public final static Hashtable objectToGlobalID=new Hashtable();
/**Table of global ID′s for local classnames.(classname-to-globalID
mappings)*/
public final static Hashtable classNameToGlobalID=new Hashtable();
/**Pending.True if a propagation is pending.*/
public static boolean pending =false;
/**Waiting.True if the FieldSend thread(s)are waiting.*/
public static boolean waiting=false;
/**Background send thread.Propagates values asthis thread is alerted
totheir alteration.*/
public void run(){
System.out.println(″FieldAlert_network_group=″+group);
System.out.println(″FieldAlert_network_port=″+port);
try{
//Create a DatagramSocket to send propagated field values.
DatagramSocket datagramSocket=
new DatagramSocket(port,InetAddress.getByName(group));
//Next,create the buffer and packet for all transmissions.
byte[]buffer=new byte[512]; //Working limit of 512 bytes
//per packet.
DatagramPacket datagramPacket=
new DatagramPacket(buffer,0,buffer.length };
while(!Thread.interrupted()){
Object[]entries=null;
//Lock the alerts table.
synchronized(FieldAlert.alerts){
//Await for an alert to propagate something.
while(!pending){
waiting=true;
FieldAlert.alerts.wait ();
waiting=false;
}
pending=false;
entries=FieldAlert.alerts.entrySet().toArray();
//Clear alerts once we have copied them.
FieldAlert.alerts.clear();
}
//Process each obj ect alert in turn.
for(int i=0;i<entries.length;i++){
FieldAlert alert=(FieldAlert)entries[i];
int index=0;
datagramPacket.setLength(buffer.length);
Object reference=null;
if(alert.reference instanceof String){
//PROPAGATE_CLASS field operation.
buffer[index++]=(byte)((PROPAGATE CLASS>>24)&0xff);
buffer[index++]=(byte)((PROPAGATE CLASS>>16)&0xff);
buffer[index++]=(byte)((PROPAGATE CLASS>>8)&0xff);
buffer[index++]=(byte)((PROPAGATE CLASS>>0)&0xff);
String name=(String)alert.reference;
int length=name.length();
buffer[index++]=(byte)((length>>24)&0xff);
buffer[index++]=(byte)((length>>16)&0xff);
buffer[index++]=(byte)((length>>8)&0xff);
buffer[index++]=(byte)((length>>0)&0xff);
byte[]bytes=name.getBytes();
System.arraycopy(bytes,0,buffer,index,length);
index+=length;
}else{ //PROPAGATE OBJECT field operation.
buffer[index++]=
(byte)((pROPAGATE OBJECT>>24)&0xff);
buffer[index++]=
(byte)((PROPAGATE OBJECT>>16)&0xff);
buffer[index++]=(byte)((PROPAGATE OBJECT>>8)&0kff);
buffer[index++]=(byte)((PROPAGATE OBJECT>>0)&0xff);
int globalID=((Integer)
objectToGlobalID.get(alert.reference)).intValue();
buffer[index++]=(byte)((globalID>>24)&0xff);
buffer [index++]=(byte)((globalID>>16)&0xff);
buffer[index++]=(byte)((globalID>>8)&0xff);
buffer[index++]=(byte)((globalID>>0)&0xff);
reference=alert.reference;
}
//Use reflection to get a table of fields that correspond to
//the field indexes used internally.
Field[]fields=null;
if(reference==null){
fields=FieldLoader.loadClass((String)
alert.reference).getDeclaredFields();
}else{
fields=alert.reference.getClass ().getDeclaredFields();
}
//Now encode in batch mode the fieldID/value pairs.
for(intj=0;j<alert.fieldAlerts.length;j++){
if(alert.fieldAlerts[j]==false)
continue;
buffer[index++]=(byte)((j>>24)&0xff);
buffer[index++]=(byte)((j>>16)&0xff);
buffer[index++]=(byte)((j>>8)&0xff);
buffer[index++]=(byte)((j>>0)&0xff);
//Encode value.
Class type=fields[j].getType();
if(type==Boolean.TYPE){
buffer[index++]=(byte)
(fields[j].getBoolean(reference)?1:0);
}else if(type==Byte.TYPE){
buffer[index++]=fields[j].getByte(reference);
}else if(type==Short.TYPE){
short v=fields[j].getshort(reference);
buffer[index++]=(byte)((v>>8)&0xff);
buffer[index++]=(byte)((v>>0)&0xff);
}else if (type==Character.TYPE){
char v =fields[j].getChar (reference);
buffer[index++]=(byte)((v>>8)&0xff);
buffer[index++]=(byte)((v>>0)&0xff);
}else if (type==Integer.TYPE){
int v=fields[j].getInt(reference);
buffer[index++]=(byte)((v>>24)&0xff);
buffer[index++]=(byte)((v>>16)&0xff);
buffer[index++]=(byte)((v>>8)&0xff);
buffer[index++]=(byte)((v>>0)&0xff);
}else if (type==Float.TYPE){
int v=Float.floatToIntBits {
fields[j].getFloat(reference));
buffer[index++]=(byte)((v>>24)&0xff);
buffer[index++]=(byte)((v>>16)&0xff);
buffer[index++]=(byte)((v>>8)&0xff);
buffer[index++]=(byte)((v>>0)&0xff);
}else if (type==Long.TYPE){
long v=fields[j].getLong(reference);
buffer[index++]=(byte)((v>>56)&0xff);
buffer[index++]=(byte)((v>>48)&0xff);
buffer[index++]=(byte)((v>>40)&0xff);
buffer[index++]=(byte)((v>>32)&0xff);
buffer[index++]=(byte)((v>>24)&0xff);
buffer[index++]=(byte)((v>>16)&0xff);
buffer[index++]=(byte)((v>>8)&0xff);
buffer[index++]=(byte)((v>>0)&0xff);
}else if (type==Double.TYPE){
long v=Double.doubleToLongBits(
fields[j].getDouble(reference));
buffer[index++]=(byte)((v>>56)&0xff);
buffer[index++]=(byte)((v>>48)&0xff);
buffer[index++]=(byte)((v>>40)&0xff);
buffer[index++]=(byte)((v>>32)&0xff);
buffer[index++]=(byte)((v>>24)&0xff);
buffer[index++]=(byte)((v>>16)&0xff);
buffer[index++]=(byte)((v>>8)&0xff);
buffer[index++]=(byte)((v>>0)&0xff);
}else{
throw new AssertionError(″Unsupported type.″);
}
}
//Now set the length of the datagrampacket.
datagramPacket.setLength(index);
//Now send the packet.
datagramSocket.send(datagramPacket);
}
}
}catch (Exception e){
throw new AssertionError(″Exception:″+e.toString());
}
}
}
A10.第十摘录是FieldReceive的源代码,其接收经由FieldSend发送的所传播的改变的值。
- - - -
import java.lang.*;
import java.lang.reflect.*;
import java.util.*;
import java.net.*;
import java.io.*;
public class FieldReceive implements Runnable{
/**Protocol specific values.*/
public final static int CLOSE=-1;
public final static int NACK=0;
public final static int ACK=1;
public final static int PROPAGATE_OBJECT=10;
public final static int PROPAGATE CLASS=20;
/**FieldAlert network values.*/
public final static String group=
System.getProperty (″FieldAlert_network_group″);
public final static int port=
Integer.parseInt(System.getProperty(″FieldAlert_network_port″));
/**Table of globalID′s for localobjects.(globalID-to-hasbcode
mappings)*/
public final static Hashtable globalIDToObject=new Hashtable();
/**Table of global ID′s for local classnames.(globalID-to-classname
mappings)*/
public final static Hashtable globalIDToClassName=new Hashtable();
/**Called when an application is to acguire a lock.*/
public void run(){
System.out.println(″FieldAlert_network_group-″+group);
System.out.println(″FieldAlert_network_Port=″+port);
try{
//Create a DatagramSocketto send propagated field values from
MulticastSocket multicastSocket=new MulticastSocket(port);
multicastSocket.j oinGroup(InetAddress.getByName (group));
//Next,create the buffer and packet for.all transmissions.
byte[]buffer=new byte[512]; //Working limit of 512
//bytes per packet.
DatagramPacket datagramPacket=
new DatagramPacket(buffer,0,buffer.length);
while (!Thread.interrupted()){
//Make sure to reset length.
datagramPacket.setLength(buffer.length);
//Receive the next available packet.
multicastSocket.receive(datagramPacket);
int index=0,length=datagramPacket.getLength();
//Decode the command.
int command=(int)(((buffer[index++]&0xff)<<24)
|((buffer[index++]&0xff)<<16)
|((buffer[index++]&0xff)<<8)
|(buffer[index++]&0xff));
if(command==PROPAGATE OBJECT){ //Propagate operation for .
//object fields.
//Decodeglobal id.
int globalID=(int)(((buffer[index++]&0xff)<<24)
|((buffer [index++]&0xff)<<16)
|((buffer[index++]&0xff)<<8)
|(buffer[index++]&0xff));
//Now,need to resolve the objectin question.
Object reference=globalIDToObject.get (
new Integer(globalID));
//Next,get the array of fields forthis object.
Field[]fields=reference.getClass().getDeclaredFields();
while(index<length){
//Decode the field id.
int fieldID=(int)(((buffer[index++]&0xff)<<24)
|((buffer[index++]&0xff)<<16)
|((buffer[index++]&0xff)<<8)
|(buffer[index++]&0xff));
//Determine value length based on corresponding field
//type.
Field field=fields[fieldID];
Class type=field.getType();
if(type==Boolean.TYPE){
boolean v=(buffer[index++]==1?true:false);
field.setBoolean (reference,v);
}else if(type.==Byte.TYPE){
byte v=buffer.[index++];
field.setByte(reference,v);
}else if(type==Short.TYPE){
short v=(short)(((buffer[index++]&0xff)<<8)
|(buffer[index++]&0xff));
field.setShort(reference,v);
}else if (type ==Character.TYPE){
char v=(char)(((buffer[index++]&0xff)<<8)
|(buffer [index++]&0xff));
field.setChar (reference,v);
}else if (type==Integer.TYPE){
int v=(int)(((buffer[index++]&0xff)<<24)
|((buffer[index++]&0xff)<<16)
|((buffer[index++]&0xff)<<8)
|(buffer[index++]&0xff));
field.setInt(reference,v);
}else if (type==Float.TYPE){
intv=(int)(((buffer[index++]&0xff)<<24)
|((buffer[index++]&0xff)<<16)
|((buffer[index++]&0xff)<<8)
|(buffer[index++]&0xff));
field.setFloat(reference,Float.intBitsToFloat(v));
}else if (type==Long.TYPE){
long v=(long )(((buffer[index++]&0xff)<<56)
|((buffer[index++]&0xff)<<48)
|((buffer[index++]&0xff)<<40)
|((buffer[index++]&0xff)<<32)
|((buffer[index++]&0xff)<<24)
|((buffer[index++]&0xff)<<16)
|((buffer[index++]&0xff)<<8)
|(buffer[index++]&0xff));
field.setLong(reference,v);
}else if (type==Double.TYPE){
long v=(long)(((buffer[index++]&0xff)<<56)
|((buffer[index++]&0xff)<<48)
|((buffer[index++]&0xff)<<40)
|((buffer[index++]&0xff)<<32)
|((buffer[index++]&0xff)<<24)
|((buffer[index++]&0xff)<<16)
|((buffer[index++]&0xff)<<8)
|(buffer[index++]&0xff));
field.setDouble(reference,Double.longBitsToDouble(v)};
}else{
throw new AssertionError(″Unsupported type.″);
}
}
}else if (command==PROPAGATE CLASS){ //Propagate an update
//to class fields.
//Decode the classname.
int nameLength=(int)(((buffer[index++]&0xff)<<24)
|((buffer[index++]&0xff)<<16)
|((buffer[index++]&0xff)<<8)
|(buffer[index++]&0xff));
String name=new String(buffer,index,nameLength);
index +=nameLength;
//Next,get the array of fields for this class.
Field[]fields =
FieldLoader.loadClass(name).getDeclaredFields();
//Decode all batched fields included in this propagation
//packet.
while (index<length){
//Decodethe field id.
int fieldID=(int)(((buffer[index++]&0xff)<<24)
|((buffer[index++].&0xff)<<16)
|((buffer[index++]&0xff)<<8)
|(buffer[index++]&0xff));
//Determine field type to determine value length.
Field field=fields[fieldID];
Class type=field.getType();
if (type==Boolean.TYPE){
boolean v=(buffer[index++]==1?true :false);
field.setBoolean(null,v);
}else if (type==Byte.TYPE){
byte v=buffer[index++];
field.setByte(null,v);
}else if (type ==Short.TYPE){
short v=(short)(((buffer[index++]&0xff)<<8)
|(buffer[index++]&0xff));
field.setShort(null,v);
}else if (type==Character.TYPE){
char v=(char)(((buffer[index++]&0xff)<<8)
|(buffer[index++]&0xff)};
field.setChar(null,v);
}else if (type==Integer.TYPE){
int v=(int)(((buffer[index++]&0xff)<<24)
|((buffer[index++]&0xff)<<16)
|((buffer[index++]&0xff)<<8)
|(buffer[index++]&0xff));
field.setInt(null,v);
}else if (type==Float.TYPE){
int v=(int)(((buffer[index++]&0xff)<<24)
|((buffer[index++]&0xff)<<16)
|((buffer[index++]&0xff)<<8)
|(buffer[index++]&0xff));
field.setFloat(null,Float.intBitsToFloat(v));
}else if (type==Long.TYPE){
long v=(long)(((buffer [index++]&0xff)<<56)
|((buffer[index++]&0xff)<<48)
|((buffer[index++]&0xff)<<40)
|((buffer[index++]&0xff)<<32)
|((buffer[index++]&0xff)<<24)
|((buffer[index++]&0xff)<<16)
|((buffer[index++]&0xff)<<8)
|(buffer [index++]&0xff));
field.setLong(null,v);
}else if (type==Double.TYPE){
long v=(long)(((buffer[index++]&0xff)<<56)
|((buffer[index++]&0xff)<<48)
|((buffer[index++]&0xff)<<40)
|((buffer[index++]&0xff)<<32)
|((buffer[index++]&0xff)<<24)
|((buffer[index++]&0xff)<<16)
|((buffer[index++]&0xff)<<8)
|(buffer[index++]&0xff));
field.setDouble(null,Double.longBitsToDouble(v));
}else{//Unsupported fieldtype.
throw new AssertionError(″Unsupported type.″);
}
}
}
}
}catch (Exception e){
throw new AssertionError(″Exception:″+e.toString());
}
}
}
A11.FieldLoader.java
该摘录是FieldLoader的源代码,其在加载应用时对其进行修改。
import java.lang.*;
import java.io.*;
import java.net.*;
public class FieldLoader extends URLClassLoader{
public FieldLoader(URL[]urls){
super (urls);
}
protected Class findClass(String name)
throws ClassNotFoundException {
ClassFile cf=null;
try{
BufferedInputStream in =
new BufferedInputStream(findResource{
name.replace(′.′,′/′).concat(″.class″)).openStream());
cf=new ClassFile(in);
}catch (Exception e){throw new ClassNotFoundException(e.toString());}
//Class-wide pointers to the ldc and alert index.
intldcindex=-1;
int alertindex=-1;
for (int i=0;i<cf.methods_count ;i++){
for (intj=0;j<cf.methods[i].attributes_count;j++){.
if (!(cf.methods[i].attributes[j]instanceof Code_attribute))
continue;
Code_attribute ca=(Code_attribute)cf.methods[i].attributes[j];
boolean changed=false;
for (int z=0;z<ca.code.length;z++){
if ((ca.code[z][0]&0xff)==179){ //Opcode for a
PUTSTAT IC
//instruction.
changed=true;
//The code below only supports fields in this class.
//Thus,first off,check that this field is local to this
//class.
CONSTANT_Fieldref_info fi=(CONSTANT_Fieldref_info)
cf.constant_pool[(int)(((ca.code[z][1]&0xff)<<8)|
(ca.code[z][2]&0xff))];
CONSTANT_Class_info ci=(CONSTANT_Class_info)
cf.constant_pool[fi.class_index];
String className=
cf.constant_pool[ci.name_index].toString();
if (!name.equals(className)){
throw new AssertionError(″This codeonly supports
fields″
″localto this class″);
}
//Ok,now search for the fields name and index.
int index=0;
CONSTANT_NameAndType_info ni=(CONSTANT_NameAndType_info)
cf.constant_pool[fi.name_and_type_index];
StringfieldName=
cf.constant_pool[ni.name_index].toString();
for (int a=0;a<cf.fields_count;a++){
String fn=cf.constant_pool{
cf.fields[a].name_index].toString();
if (fieldName.equals(fn)){
index=a;
break;
}
}
//Next,realign the code array,making room for the
//insertions.
byte[][]code2=new byte[ca.code.length+3][];
System.arraycopy(ca.code,0,code2,0,z+1);
System.arraycopy(ca.code,z+1,code2,z+4,
ca.code.length-(z+1));
ca.code=code2;
//Next,insert the LDC_W instruction.
if (ldcindex ==-1){
CONSTANT_String_info csi=
new CONSTANT_String_info(ci.name_index);
cp_info[]cpi =new cp_info[cf.constant_pool.length+1];
System.arraycopy(cf.constant_pool ,0,cpi,0,
cf.constant_pool.length);
cpi[cpi.length-1]=csi;
ldcindex=cpi.length-1;
cf.constant_pool=cpi;
cf.constant_pool_count++;
}
ca.code[z+1]=new byte[3];
ca.code [z+1][0]=(byte)19;
ca.code[z+1][1]=(byte)((ldcindex>>8)&0xff);
ca.code[z+1][2]=(byte)(ldcindex&0xff);
//Next,insert the SIPUSHinstruction.
ca.code[z+2]=new byte[3];
ca.code[z+2][0]=(byte)17;
ca.code[z+2][1]=(byte)((index>>8)&0xff);
ca.code[z+2][2]=(byte)(index&0xff);
//Finally,insert the.INVOKESTATIC instruction.
if (alertindex==-1){
//This isthe first time this class is encourtering
the
//alert instruction,so have to add it to the constant
//pool.
cp_info[]cpi=new cp_info [cf.constant_pool.length+6];
System.arraycopy(cf.constant_pool,0,cpi,0,
cf.constant_pool.length);
cf.constant_pool=cpi;
cf.constant_pool_count+=6;
CONSTANT_Utf8_info u1=
new CONSTANT_Utf8_info(″FieldAlert″);
cf.constant_pool[cf.constant_pool.length-6]=u1;
CONSTANT_Class_info cl=new CONSTANT_Class_info (
cf.constant_pool_count-6);
cf.constant_pool[cf.constant_pool.length-5]=c1;
u1=new CONSTANT_Utf8_info(″alert″);
cf.constant_pool[cf.constant_pool.length-4]=u1;
u1=new CONSTANT_Utf8_info(″(Ljava/lang/Object;I)V″);
cf.constant_pool[cf.constant_pool.length-3]=u1;
CONSTANT_NameAndType_info n1=
new CONSTANT_NameAndType_info{
cf.constant_pool.length-4,cf.constant_pool.length-
3);
cf.constant_pool[cf.constant_pool.length-2]=n1;
CONSTANT_Methodref_info m1=new
CONSTANT_Methodref_info{
cf.constant_pool.length-5,cf.constant_pool.length-
2);
cf.constant_pool[cf.constant_pool.length-1]=m1;
alertindex=cf.constant_pool.length-1;
}
ca.code[z+3]=new byte[3];
ca.code[z+3][0]=(byte)184;
ca.code[z+3][1]=(byte)((alertindex>>8)&0xff);
ca.code[z+3][2]=(byte)(alertindex&0xff);
//And lastly,increase the CODE_LENGTH and
ATTRIBUTE_LENGTH
//values.
ca.code_length+=9;
ca.attribute_length+=9;
}
}
//If we changed this method,thenincrease the stack size by
one.
if (changed){
ca.max_stack++;//Just to make sure.
}
}
}
try{
ByteArrayOutputStream out=new ByteArrayOutputStream();
cf.serialize(out);
byte[]b=out.toByteArray();
return defineClass(name ,b,0,b.length);
}catch (Exception e){
throw new ClassNotFoundException(name);
}
}
}
fields″A12.AttribUte_info.java
fields″用于表示ClassFile内的attribUte_info结构的Convience类。
import java.lang.*;
import java.io.*;
/**This abstract class represents all types of attribute_info
*that are used in theJVM specifications.
*
*All new attribute_info subclasses are toalways inherit from this
*class.
*/
public abstract class attribute info{
public int attribute name index;
public int attribute_length;
/**This is used by subclasses to register themselves
*totheir parent classFile.
*/
attribute_info(ClassFile cf){}
/**Used during input serialization by ClassFile only.*/
attribute_info(ClassFile cf,DataInputStream in)
throws IOException{
attribute name index =in.readChar();
attribute_length=in.readInt ();
}
/**Used during output serialization by ClassFile only.*/
void serialize(DataOutputStream out)
throws IOException{
out.writeChar(attribute_name_index);
out.writeInt(attribute length);
}
/**This class represents an unknown attribute_info that
*this currentversion of classfile specification does
*not understand.
*/
public final static class Unknown extends attribute_info{
byte[]info;
/**Used during input serialization by ClassFile only.*/
Unknown (ClassFile cf,DataInputStream in)
throws IOException{
super(cf,in);
info=new byte[attribute length];
in.read(info,0,attribute_lemgth);
}
/**used during output serialization by ClassFile only.*/
void serialize(DataOutputStream out)
throws IOException{
ByteArrayOutputStream baos=new ByteArrayOutputStream();
super.serialize(out);
out.write(info,0,attribute_length);
}
}
}
A13.ClassFile.java
用于表示ClassFile结构的Convience类。
importjava.lang.*;
import java.io.*;
import java.util.*;
/**The ClassFile follows verbatim from the JVM specification.*/
public final class ClassFile {
public int magic;
public int minor_version;
public intmaj or_version;
public int constant_pool_count;
public cp_info[]constant_pool;
public int access_flags ;
public int this_class;
public int super_class ;
public int interfaces_count;
public int[]interfaces;
public int fields_count;
public field_info[]fields ;
public int methods_count;
public method_info[] methods;
public int attributes_count ;
public attribute_info[]attributes;
/**Constructor.Takes in a byte stream representation and transforms
*each of the attributes in the ClassFile into objects to allow for
*easier manipulation.
*/
public Class File(InputStream ins)
throws IOException{
DataInputStreamin=(ins instanceof DataInputStream?
(DataInputStream)ins:new DataInputStream(ins));
magic=in.readInt();
minor_version=in.readChar();
major_version=in.readChar();
constant_pool_count=in.readChar();
constant_pool=new cp_info [constant_pool_count];
for (int i=1;i<constant_pool_count;i++){
in.mark(1);
int s=in.read();
in.reset();
switch (s){
case 1:
constant_pool[i]=new CONSTANT_Utf8_info(this,in);
break;
case 3:
constant_pool[i]=new CONSTANT_Integer_info(this,in);
break;
case 4:
constant_pool[i]=new CONSTANT_Float_info(this,in);
break;
case 5:
constant_pool[i]=new CONSTANT_Long_info(this,in);
i++;
break;
case 6:
constant_pool[i]=new CONSTANT_Double_info(this,in);
i++;
break;
case 7:
constant_pool[i]=new CONSTANT_Class_info(this,in);
break;
case 8:
constant_pool[i]=new CONSTANT_String_info(this,in);
break;
case 9:
constant_pool[i]=new CONSTANT_Fieldref_info(this,in);
break;
case 10:
constant_pool[i]=new CONSTANT_Methodref_info(this,in);
break;
case 11:
constant_pool[i]=
new CONSTANT_InterfaceMethodref_info(this,in);
break;
case 12:
constant_pool[i]=new CONSTANT_NameAndType_info(this,
in);
break;
default:
throw new ClassFormatError(″Invalid ConstantpoolTag″);
}
}
access_flags=in.readChar();
this_class=in.readChar();
super_class=in.readChar();
interfaces_count =in.readChar();
interfaces=new int[interfaces_count];
for (int i=0;i<interfaces_count;i++)
interfaces[i]=in.readChar();
fields_count=in.readChar();
fields=new field_info{fields count];
for (int i=0;i<fields_count;i++){
fields[i]=new field_info(this,in);
}
methods_count=in.readChar();
methods =new method_info[methods_count];
for (int i=0;i<methods_count;i++){
methods[i]=new method_info(this,in);
}
attributes_count=in.readChar ();
attributes=new attribute_info.[attributes count];
for (inti=0;i<attributes_count;i++){
in.mark(2);
String s=constant_pool[in.readChar()].toString();
in.reset();
if (s.equals (″SourceFile″))
attributes[i]=new SourceFile_attribute(this,in);
else if (s.equals(″Deprecated″))
attributes[i]=new Deprecated_attribute(this,in);
else if (s.equals(″InnerClasses″))
attributes[i]=new InnerClasses_attribute(this ,in);
else
attributes[i]=new attribute_info.Unknown(this,in);
}
}
/**Serializes the ClassFile object into a byte stream.*/
public void serialize(OutputStream o)
throws IOException{
DataOutputStream out=(o instanceof DataOutputStream?
(DataOutputStream)o:new DataOutputStream(o));
out.writeInt(magic);
out.writeChar(minor_version);
out.writeChar(major_version);
out.writeChar(constant_pool_count);
for (int i=1;i<constant_pool_count;i++){
constant_pool[i].serialize(out);
if (constant_pool[i]instanceof CONSTANT_Long_info ||
constant_pool[i]instanceof CONSTANT_Double_info)
i++;
}
out.writeChar(access_flags);
out.writeChar(this_class);
out.writeChar(super_class);
out.writeChar(interfaces_count);
for (int i=0;i<interfaces_count;i++)
out.writeChar(interfaces[i]);
out.writeChar (fields_count);
for (int i=0;i<fields_count;i++)
fields[i].serialize(out);
out:writeChar(methods_count);
for (int i=0;i<methods_count;i++)
methods[i].serialize(out);
out.writeChar (attributes_count);
for (inti=0;i<attributes_count;i++)
attributes[i].serialize(out);
//Flushthe outputstream just to make sure.
out.flush();
}
}
A14.Code_attribute.java
用于表示ClassFile内的Code_attribute结构的Convience类。
import java.util.*;
import java.lang.*;
import java.io.*;
/**
*The code[]is stored as a 2D array.*/
public final class Code_attribute extends attribute_info{
public int max_stack;
public int_max_locals;
public int code_length;
public byte[][]code;
public int exception_table_length;
public exception_table[]exception_table;
public int attributes_count;
public attribute_info[]attributes;
/**Internal class that handles the exception table.*/
public final static class exception_table{
public int stsrt_pc;
public int end_pc;
public int handler_pc;
public int catch_type;
}
/**Constructor called only by method_info.*/
Code_attribute(ClassFile cf,int ani,int al,int ms,int ml,int cl,
byte[][]cd,int etl,exception_table[]et,int ac,
attribute_info[]a){
super(cf);
attribute_name_index =ani;
attribute_length=al;
max_stack=ms;
max_locals=ml;
code_length=cl;
code_=cd;
exception_table_length=etl;
exception_table =et ;
attributes_count=ac;
attributes =a;
}
/**Used duringinput serialization by ClassFile only.*/
Code_attribute(ClassFile cf,DataInputStream in)
throws IOException{
super(cf,in);
max_stack=in.readChar();
max_locals=in.readChar();
code_length=in.readInt();
code=new byte[code_length][];
inti=0;
for (intpos=0;pos<code_length;i++){
in.mark(1);
int s=in.read();
in.reset ();
switch (s){
case 16:
case 18:
case 21:
case 22:
case 23:
case 24:
case 25:
case 54:
case 55:
case 56:
case 57:
case 58:
case 169:
case 188:
case 196:
code[i]=new byte[2];
break;
case 17:
case 19:
case 20:
case 132:
case 153:
case 154:
case 155:
case 156:
case 157:
case 158:
case 159:
case 160:
case 161:
case 162:
case 163:
case 164:
case 165:
case 166:
case 167:
case 168:
case 178:
case 179:
case 180:
case 181:
case 182:
case 183:
case 184:
case 187:
case 189:
case 192:
case 193:
case 198:
case 199:
case 209:
code[i]=new byte[3];
break;
case 197:
code[i]=new byte[4];
break;
case 185:
case 200:
case 201:
code[i]=new byte[5];
break;
case 170:{
in.mark (pad+13);//highbyte
in.skipBytes(pad+5);//lowbyte
int low =in.readInt();
code[i]=
new byte[pad+13+((in.readInt()-low+1)*4)];
in.reset();
break;
}case 171:{
in.mark(pad+9);
in.skipBytes(pad+5);
code[i]=new byte[pad+9+(in.readInt()*8)];
in.reset();
break;
}default:
code[i]=new byte[1];
}
in.read(code[i],0,code[i].length);
pos+=code[i].length;
}
//adj ust the array to the new size and store the size
byte[][]temp=new byte[i][];
System.arraycopy(code,0,temp,0,i);
code=temp;
exception_table_length=in.readChar();
exception_table=
new Code_attribute.exception_table[exception_table_length];
for (i=0;i<exception_table_length;i++){
exception_table[i]=new exception_table ();
exception_table[i].start_pc=in.readChar();
exception_table[i].end_Pc=in.readChar();
exception_table[i].handler_pc=in.readChar();
exception_table[i].catch_type=in.readChar();
}
attributes count=in.readChar();
attributes=new attribute info[attributes count];
for (i=0;i<attributes count;i++){
in.mark(2);
String s=cf.constant_pool[in.readChar ()].toString();
in.reset();
if (s.equals(″LineNumberTable″))
attributes[i]=new LineNumberTable attribute(cf,in);
else if (s.equals(″LocalVariableTable″))
attributes[i ]=new LocalVariableTable attribute(cf,in);
else
attributes [i]=new attribute info.Unknown(cf,in);
}
}
/**Used during output serialization by ClassFile only.
*/
void serialize (DataOutputStream out)
throws IOException{
attribute_length=12+code_length+
(exception_table_length *8);
for (int i=0;i<attributes_count;i++)
attribute_length+=attributes[i].attribute_length+6;
super.serialize(out);
out.writeChar (max_stack);
out.writeChar(max_locals);
out.writeInt(code_length);
for (inti=0,pos=0;pos<code_length;i++){
out.write(code[i],0,code[i].length);
pos+=code[i].length;
}
out.writeChar(exception_table_length);
for (int i=0;i<exception_table_length;i++){
out.writeChar(exception_table[i].start_pc);
out.writeChar (exception_table[i].end_pc);
out.writeChar(exception_table[i].handler_pc);
out.writeChar(exception_table[i].catch_type);
}
out.writeChar(attributes_count);
for (int i=0;i<attributes_count;i++)
attributes[i].serialize(out);
}
}
A15.CONSTANT_Class_info.java
用于表示ClassFile内的CONSTANT_Class_info结构的Convience类。
import java.lang.*;
import java.io.*;
/**Class subtype of a constantpool entry.*/
public final class CONSTANT_Class_info extends cp_info{
/**The index to the name of this class.*/
public int name_index=0;
/**Convenience constructor.
*/
public CONSTANT_Class_info(intindex){
tag=7;
name_index=index;
}
/**Used during input serialization by Class File only.*/
CONSTANT_Class_info(ClassFile cf,DataInputStream in)
throwsIOException{
super(cf,in);
if(tag !=7)
throw new ClassFormatError();
name_index =in.readChar ();
}
/**Used during outputserialization by ClassFile only.*/
void serialize(DataOutputStream out)
throws IOException{
out.writeByte(tag);
out.writeChar(name_index);
}
}
A16.CONSTANT Double_info.java
用于表示ClassFile内的CONSTANT Double info结构的Convience类。
import java.lang.*;
import java.io.*;
/**Double subtype of a constant pool entry.*/
public final class CONSTANT_Double_info extends cp_info{
/**The actual value.*/
public double bytes ;
public CONSTANT_Double_info(double d){
tag=6;
bytes=d;
}
/**Used during input serialization by ClassFile only.*/
CONSTANT_Double_info(ClassFile cf,DataInputStream in)
throws IOException{
super{cf,in);
if (tag !=6)
throw new ClassFormatError(};
bytes=in.readDouble ();
}
/**Used during output serialization by ClassFile only.*/
void serialize{DataOutputStream out)
throws IOException{
out.writeByte(tag);
out.writeDouble(bytes);
long l =Double.doubleToLongBits(bytes);
}
}
A17.CONSTANT_Fieldref_info.java
用于表示ClassFile内的CONSTANT_Fieldref_info结构的Convience类。
import java.lang.*;
import java.io.*;
/**Fieldref subtype of a constant pool entry.*/
public final class CONSTANT_Fieldref_info extends cp_info{
/**The index to the class that this field is referencing to.*/
public int class_index;
/**The name and type index this field if referencing to.*/
public intname_and_type_index;
/**Convenience const ructor.*/
public CONSTANT_Fieldref_info(int class_index,int name_and_type_index)
{
tag=9;
this.class_index=class_index;
this.name_and_type_index=name_and_type_index ;
}
/**Used during input serialization by ClassFile only.*/
CONSTANT_Fieldref_info(ClassFile cf,DataInputStream in)
throws IOException {
super(cf,in);
if (tag !=9)
throw new ClassFormatError();
class_index=in.readChar();
name_and_type_index=in.readChar();
}
/**Used during output serialization by ClassFile only.*/
void serialize(DataOutputStream out)
throws IOException [
out.writeByte(tag);
out.writeChar(class_index);
out.writeChar(name_and_type_index);
}
}
A18.CONSTANT_Float_info.java
用于表示ClassFile内的CONSTANT_Float_info结构的Convience类。
import java.lang.*;
import java.io.*;
/**Float subtype of a constant pool entry.*/
public final class CONSTANT_Float_info extends cp_info{
/**The actual value.*/
public float bytes ;
public CONSTANT_Float_info (float f){
tag=4;
bytes=f;
}
/**Used during input serialization by ClassFile only.*/
CONSTANT_Float_info(ClassFile cf,DataInputStream in)
throws IOExcept ion{
super(cf,in);
if (tag !=4)
throw new ClassFormatError();
bytes=in.readFloat ();
}
/**Used during output serialization by ClassFile only.*/
public void serialize (DataOutputStream out)
throws IOException{
out.writeByte(4);
out.writeFloat(bytes);
}
}
A19.CONSTANT_Integer_info.java
用于表示ClassFile内的CONSTANT_Integer_info结构的Convience类。
import java.lang.*;
import java.io.*;
/**Integer subtype of a constant pool entry.*/
public final class CONSTANT_Integer_info extends cp_info{
/**The actual value.*/
public int bytes;
public CONSTANT_Integer_info(int b){
tag=3;
bytes=b;
}
/**Used during input serialization by ClassFile only.*/
CONSTANT_Integer_info(ClassFile cf,DataInputStream in)
throws IOException {
super(cf,in);
if (tag!=3)
throw new ClassFormatError();
bytes=in.readInt();
}
/**Used during output serialization by ClassFile only.*/
public void serialize(DataOutputStream out)
throws IOException{
out.writeByte(tag);
out.writeInt(bytes);
}
}
A20.CONSTANT_InterfaceMethodref_info.java
用于表示ClassFile内的CONSTANT_InterfaceMethodref_info结构的Convience类。
import java.lang.*;
import java.io.*;
/**InterfaceMethodref subtype of a constant pool entry.
*/
public final class CONSTANT_InterfaceMethodref_info extends cp_info{
/**The indexto the class thatthis field is referencing to.*/
public int class_index;
/**The name and type index this field if referencing to.*/
public int name_and_type_index;
public CONSTANT_InterfaceMethodref_info (int class_index,
int name_and_type_index){
tag =11;
this.class_index=class_index;
this.name_and_type_index=name_and_type_index;
}
/**Used during input serialization by ClassFile only.*/
CONSTANT_InterfaceMethodref_info(ClassFile cf,DataInputStream in)
throws IOException {
super(cf,in);
if (tag!=11)
throw new ClassFormatError();
class_index=in.readChar();
name_and_type_index=in.readChar();
}
/**Used during outputserialization by ClassFile only.*/
void serialize(DataOutputStream out)
throws IOException{
out.writeByte(tag);
out.writeChar(class_index);
out.writeChar(name_and_type_index);
}
}
A21.CONSTANT_Long_info.java
用于表示ClassFile内的CONSTANT_Long_info结构的Convience类。
import java.lang.*;
import java.io.*;
/**Long subtype of a constant pool entry.*/
public final class CONSTANT_Long_info extends cp_info{
/**The actual value.*/
public long bytes;
public CONSTANT_Long_info(long b){
tag=5;
bytes=b;
}
/**Used during inputserialization by ClassFileonly.*/
CONSTANT_Long_info(ClassFile cf,DataInputStream in)
throws IOException{
super (cf,in);
if (tag !=5)
throw new ClassFormatError();
bytes=in.readLong ();
}
/**Used during output serialization by ClassFile only.*/
void serialize(DataOutputStream out)
throws IOException{
out.writeByte(tag);
out.writeLong(bytes);
}
}
A22.CONSTANT_Methodref_info.java
用于表示ClassFile内的CONSTANT_Methodref_info结构的Convience类。
import java.lang.*;
import java.io.*;
/**Methodref subtype of a constant pool entry.
*/
public final class CONSTANT_Methodref_info extends cp_info{
/**The index to the class that this field is referencing to.*/
public int class_index;
/**The name and type index this field if referencing to.*/
public int name_and_type_index;
public CONSTANT_Methodref_info(int class_index,int name_and_type_index)
{
tag=10;
this.class_index =class_index;
this.name_and_type_index=name_and_type_index;
}
/**Used during input serialization by ClassFile only.*/
CONSTANT_Methodref_info(ClassFile cf,DataInputStream in)
throwsIOException{
super(cf,in);
if (tag!=10)
throw new Class FormatError();
class_index=in.readChar();
name_and_type_index=in.readChar ();
}
/**Used during output serializationby ClassFile only.*/
void serialize(DataOutputStream out)
throws IOException{
out.writeByte(tag);
out.writeChar(class_index);
out.writeChar(name_and_type_index);
}
}
A23.CONSTANT_NameAndType_info.java
用于表示ClassFile内的CONSTANT_NameAndType_info结构的Convience类。
import java.io.*;
import java.lang.*;
/**NameAndType subtype of a constant pool entry.
*/
public final class CONSTANT_NameAndType_info extends cp_info{
/**The index to the Utf8 thatcontains the name.*/
public int name_index;
/**The index fo the Utf8 that constains the signature.*/
public int descriptor_index;
public CONSTANT_NameAndType_info(int name_index,int descriptor_index }{
tag=12;
this.name_index=name_index;
this.descriptor_index=descriptor_index;
}
/**Used duringinput serialization by ClassFile only.*/
CONSTANT_NameAndType_info (ClassFile cf ,DataInputStream in)
throws IOException{
super(cf,in);
if(tag !=12)
throw new Class FormatError();
name_index=in.readChar();
descriptor_index=in.readChar();
}
/**Used during output serialization by ClassFile only.*/
void serialize(DataOutputStream out)
throws IOException {
out.writeByte(tag);
out.writeChar(name_index);
out.writeChar(descriptor_index);
}
}
A24.CONSTANT_String_info.java
用于表示ClassFile内的CONSTANT_String_info结构的Convience类。
import java.lang.*;
import java.io.*;
/**String subtype of a constant pool entry.
*/
public final class CONSTANT_String_info extends cp_info {
/**The index tothe actual value of the string.*/
public int string_index;
public CONSTANT_String_info(int value){
tag=8;
string_index =value;
}
/**ONLY TO BE USED BY CLASSFILE!*/
public CONSTANT_String_info(ClassFile cf,DataInputStream in)
throws IOException{
super(cf,in);
if (tag !=8)
throw new ClassFormatError();
string_index=in.readChar();
}
/**Outputserialization,ONLY TO BE USED BY CLASSFILE!*/
public void serialize(DataOutputStream out)
throws IOExcept ion{
out.writeByte(tag);
out.writeChar(string_index);
}
}
A25.CONSTANT_Utf8_info.java
用于表示ClassFile内的CONSTANT_Utf8_info结构的Convience类。
import java.io.*;
import java.lang.*;
/**Utf8 subtype of a constant pool entry.
*We internally represent the Utf8info byte array
*as a String.
*/
public final class CONSTANT_Utf8_info extends cp_info{
/**Length of the byte array.*/
public int length;
/**The actual bytes,represented by a String.*/
public String bytes;
/**This constructor should be used for the purpose
*of part creation.It does not set the parent
*ClassFile reference.
*/
public CONSTANT_Utf8_info(String s){
tag=1;
length=s.length();
bytes=s;
}
/**Used during input serialization by ClassFile only.*/
public CONSTANT_Utf8_info(ClassFile cf,DataInputStream in)
throws IOException {
super(cf,in);
if (tag !=1)
throw new ClassFormatError();
length=in.readChar();
byte[]b=new byte[length];
in.read(b,0,length);
//WARNING:String constructor is deprecated.
bytes=new String(b,0,length);
}
/**Used during output serialization by ClassFile only.*/
public void serialize(0ataOutputStream out)
throws IOException{
out.writeByte(tag);
out.writeChar(length);
//WARNING:Handling of String coversion here might be problematic.
out.writeBytes(bytes );
}
public String toString (){
return bytes;
}
}
A26.ConstantValue_attribute.java
用于表示ClassFile内的ConstantValue_attribute结构的Convience类。
import java.lang.*;
import java.io.*;
/**Attribute that allows for initialization of static variables in
*classes.Thisattribute will only reside in a field info_struct.
*/
public final class ConstantValue_attribute extends attribute_info {
public int constantvalue_index;
public ConstantValue_attribute (ClassFile cf,int ani,int al,int cvi){
super(cf);
attribute_name_index=ani;
attribute_length=al;
constantvalue_index=cvi ;
}
public ConstantValue_attribute(ClassFile cf,DataInputStream in)
throws IOException{
super(cf,in);
constantvalue_index=in.readChar();
}
public void serialize(DataOutputStream out)
throws IOException{
attribute_length=2;
super.serialize(out);
out.writeChar(constantvalue_index);
}
}
A27.cp_info.java
用于表示ClassFile内的cp_info结构的Convience类。
import java.lang.*;
import java.io.*;
/**Represents the common interface of all constant pool parts
*tha tall specific constant pool items must inherit from.
*
*/
public abstract class cp_info {
/**The type tag that signifies what kind of constant pool
*item it is*/
public int tag;
/**Used for serialization of the object back into a bytestream.*/
abstract void serialize(DataOutputStream out)throws IOException;
/**Default constructor.Simply does nothing.*/
public cp_info(){}
/**Constructor simply takes in the ClassFile as a reference to
*it′s parent
*/
public cp_info(ClassFile cf){}
/**Used during input serialization by ClassFile only.*/
cp_info(ClassFile cf,DataInputStream in)
throws IOException{
tag=in.readUnsignedByte();
}
}
A28.Deprecated_attribute.java
用于表示ClassFile内的Deprecated_attribute结构的Convience类。
import java.lang.*;
import java.io.*;
/**A fix attributed that can be located either in the ClassFile,
*field_info or the method_info attribute.Mark deprecated to
*indicate that the method,classor field has been superceded.
*/
public final class Deprecated_attribute extends attribute_info{
public Deprecated_attribute(ClassFile cf ,int ani,int al){
super(cf);
attribute_name_index=ani;
attribute_length=al;
}
/**Used during input serialization by ClassFile only.*/
Deprecated_attribute(ClassFile cf ,DataInputStream in)
throws IOException{
super(cf,in);
}
}
A29.ExCeptions_attribute.java
用于表示ClassFile内的Exceptions_attribute结构的Convience类。
import java.lang.*;
import java.io.*;
/**This is the struct where the exceptions table are located.
*<br><br>
*This attribute can only appear once in a method_info struct.
*/
public final class Exceptions_attribute extends attribute_info{
public int number_of_exceptions;
public int[]exception_index_table;
public Exceptions_attribute(ClassFile cf,int ani,int al,int noe ,
int[]eit){
super(cf);
attribute_name_index=ani;
attribute_length=al;
number_of_exceptions=noe ;
exception_index_table=eit;
}
/**Used during input serialization by ClassFile only.*/
Exceptions_attribute(ClassFile cf,DataInputStream in)
throws IOException {
super(cf,in);
number_of_exceptions=in.readChar();
exception_index_table=new int[number of exceptions];
for(int i=0;i<number_of_exceptions;i++)
exception_index_table[i]=in.readChar ();
}
/**Used during output serialization by ClassFile only.*/
public void serialize(DataOutputStream out)
throws IOExcept ion{
attribute_length=2+(number_of_exceptions*2);
super.serialize(out);
out.writeChar(number_of_exceptions);
for (int i=0;i<number_of_exceptions;i++)
out.writeChar(exception_index_table[i]);
}
}
A30.field_info.java
用于表示ClassFile内的field_info结构的Convience类。
import java.lang.*;
import java.io.*;
/**Represents the field_info structure as specified in the JVM
specification.
*/
public final class field_info{
public int access_flags;
public int name_index;
public int descriptor_index;
public int attributes_count;
public attribute_info[]attributes;
/**Convenience constructor.*/
public field_info(ClassFile cf,int flags,int ni,int di){
access_flags =flags ;
name index=ni;
descriptor_index=di ;
attributes_count=0;
attributes=new attribute_info[0];
}
/**Constructor called only during the serialization process.
*<br><br>
*This is intentionally left as package protected as we
*should not normally call this constructor directly.
*<br><br>
*Warning:the handling of len is notcorrect (after String s=...)
*/
field_info(ClassFile cf,DataInputStream in)
throws IOException{
access_flags=in.readChar();
name_index=in.readChar();
descriptor_index=in.readChar();
attributes_count=in.readChar();
attributes=new attribute_info[attributes_count];
for (int i=0;i<attributes_count;i++){
in.mark(2);
String s=cf.constant_pool[in.readChar()].toString();
in.reset ();
if (s.equals(″ConstantValue″))
attributes[i]=new ConstantValue_attribute(cf,in);
else if (s.equals(″Synthetic″))
attributes[i]=new Synthetic_attribute(cf,in);
else if (s.equals(″Deprecated″))
attributes[i]=new Deprecated_attribute(cf,in);
else
attributes [i]=new attribute_info.Unknown(cf,in);
}
}
/**To serialize the contents into the output format.
*/
public void serialize (DataOutputStream out)
throws IOExcept ion{
out.writeChar(access_flags);
out.writeChar(name_index);
out.writeChar(descriptor_index);
out.writeChar(attributes_count);
for (inti=0;i<attributes_count;i++)
attributes [i].serialize(out);
}
}
A31.InnerClasses_attribute.java
用于表示ClassFile内的InnerClasses_attribute结构的Convience类。
import java.lang.*;
import java.io.*;
/**A variable length structure that contains information about an
*inner class of this class.
*/
public final class InnerClasses_attribute extends attribute_info{
public int number_of_classes;
public classes[]classes;
public final static class classes{
int inner_class_info_index;
int outer_class_info_index ;
int inner_name_index;
int inner_class_access_flags;
}
public InnerClasses_attribute(ClassFile cf,int ani,int al,
int noc,classes[]c){
super(cf);
attribute_name_index=ani;
att ribute_length=al;
number_of_classes=noc;
classes=c;
}
/**Used during input serialization by ClassFile only.*/
InnerClasses_attribute(ClassFile cf,DataInputStream in)
throws IOException {
super(cf,in);
number_of_classes=in.readChar();
classes=new InnerClasses_attribute.classes[number_of_classes];
for(int i=0;i<number_of_classes;i++){
classes[i]=new classes();
classes[i].inner_class_info_index=in.readChar();
classes[i].outer_class_info_index =in.readChar();
classes[i].inner_name_index=in.readChar();
classes[i].inner_class_access_flags=in.readChar();
}
}
/**Used during output serialization by ClassFile only.*/
public void serialize(DataOutputStream out}
throws IOException {
attribute_length =2+(number_of_classes *8);
super.serialize(out);
out.writeChar(number_of_classes);
for (int i=0;i<number_of_classes;i++){
out.writeChar(classes[i].inner_class_info_index);
out.writeChar(classes[i].outer_class_info_index);
out.writeChar(classes[i].inner_name_index);
out.writeChar(classes[i].inner_class_access_flags);
}
}
}
A32.LineNumberTable_attribute.jaVa
用于表示ClassFile内的LineNumberTable_attribute结构的Convience类。
import java.lang.*;
import java.io.*;
/**Determines which line of the binary code relates to the
*corresponding source code.
*/
public final class LineNumberTable_attribute extends attribute_info{
public int line_number_table_length;
public line_number_table[] line_number_table;
public final static class line_number_table{
int start_pc;
int line_number;
}
public LineNumberTable_attribute(ClassFile cf,int ani,int al,int lntl,
line_number_table[]lnt){
super(cf);
attribute_name_index=ani;
attribute_length=al;
line_number_table_length=lntl;
line_number_table=lnt ;
}
/**Used during input serialization by ClassFile only.*/
LineNumberTable_attribute(ClassFile cf,DataInputStream in)
throws IOException{
super(cf,in);
line_number_table_length=in.readChar();
line_number_table=new
LineNumberTable_attribute.line_number_table[line_number_table_length];
for(int i=0;i<line_number_table_length;i++){
line_number_table[i]=new line_number_table();
line_number_table[i].start_pc=in.readChar();
line_number_table[i].line_number=in.readChar();
}
}
/**Used during output serialization by ClassFile only.*/
void serialize(DataOutputStream out)
throws IOException {
attribute_length=2+(line_number_table_length*4);
super.serialize(out);
out.writeChar(line_number_table_length);
for (int i=0;i<line_number_table_length;i++){
out.writeChar(line_number_table[i].start_pc);
out.writeChar(line_number_table[i].line_number);
}
}
}
A33.LocalVariableTable_attribute.java
用于表示ClassFile内的LocalVariableTable_attribute结构的Convience类。
import java.lang.*;
import java.io.*;
/**Used by debugger to find out howthe source file line number is linked
*to the binary code.It has many to one correspondence and is found in
*the Code_attribute.
*/
public final class LocalVariableTable_attribute extends attribute_info {
public intlocal_variable_table_length;
public local_variable_table[] local_variable_table ;
public final static class local_variable_table {
int start_pc;
int length;
int name_index;
int descriptor_index ;
int index;
}
public LocalVariableTable_attribute(ClassFile cf,int ani,int al,
int lvtl,local_variable_table[]
lvt){
super(cf);
attribute_name_index=ani;
attribute_length=al;
local_variable_table_length=lvtl;
local_variable_table=lvt;
)
/**Used during input serialization by ClassFile only.*/
LocalVariableTable_attribute(Class File cf,DataInputStream in)
throwsIOException{
super(cf,in);
local_variable_table_length=in.readChar ();
local_variable_table=new
LocalVariableTable_attribute.local_variable_table[local_variable_table_lengt
h];
for (int i=0;i<local_variable_table_length;i++){
local_variable_table[i]=new local_variable_table ();
local_variable_table[i].start_pc=in.readChar();
local_variable_table[i].length=in.readChar();
local_variable_table[i].name_index=in.readChar();
local_variable_table[i].descriptor_index=in.readChar();
local_variable_table[i].index=in.readChar();
}
}
/**Used during outputserialization by ClassFile only.*/
void serialize(DataOutputStream out)
throwsIOExcept ion(
attribute_length =2+(local_variable_table_length *10);
super.serialize(out);
out.writeChar(local_variable_table_length);
for (int i=0;i<local_variable_table_length ;i++){
out.writeChar(local_variable_table[i].start_pc);
out.writeChar(local_variable_table[i].length);
out.writeChar(local_variable_table[i].name_index);
out.writeChar(local_variable_table[i].descriptor_index);
out.writeChar(local_variable_table[i].index);
}
}
}
A34.methOd_info.java
用于表示ClassFile内的methOd_info结构的COnvienCe类。
import java.lang.*;
import java.io.*;
/**This follows the method_info inthe JVM specification.
*/
public final classmethod_info {
public int access_flags;
public int name_index;
public int descriptor_index;
public int attributes_count ;
public attribute_info[]attributes;
/**Constructor.Creates a method_info,initializes it with
*the flags set,and the name and descriptor indexes given.
*A new uninitialized code attribute is also created,and stored
*in the<i>code</i>variable.*/
public method_info(ClassFile cf,int flags,int ni,intdi,
int ac,attribute_info[1a)(
access_flags=flags;
name_index =ni;
descriptor_index =di;
attributes_count =ac;
attributes=a;
}
/**This method creates a method_info from the current pointer in the
*data stream.Only called byduringthe serialization of a complete
*ClassFile from a bytestream,notnormally invoked directly.
*/
method_info (ClassFile cf,DataInputStream in)
throws IOException {
access_flags=in.readChar();
name_index=in.readChar();
descriptor_index=in.readChar();
attributes_count =in.readChar ();
attributes=new attribute_info[attributes_count];
for (int i=0;i<attributes_count;i++){
in.mark (2);
String s=cf.constant_pool[in.readChar()].toString();
in.reset();
if (s.equals(″Code″))
attributes[i]=new Code_attribute(cf,in);
else if (s.equals(″Exceptions″))
attributes[i]=new Exceptions_attribute(cf,in);
else if (s.equals(″Synthetie″))
attributes[i]=new Synthetic_attribute(cf,in);
else if (s.equals(″Deprecated″))
attributes[i]=new Deprecated_attribute(cf,in);
else
attributes[i]=new attribute_info.Unknown(cf,in);
}
}
/**Outputserialization of the method_info to a byte array.
*Not normally invoked directly.
*/
public void serialize(DataOutputStream out)
throws IOException {
out.writeChar (access_flags);
out.writeChar (name_index);
out.writeChar(descriptor_index);
out.writechar(attributes_count);
for (int i=0;i<attributes_count ;i++)
attributes[i].serialize(out);
}
}
A35.SourceFile_attribute.java
用于表示ClassFile内的SourceFile_attribute结构的Convience类。
import java.lang.*;
import java.io.*;
/**A SourceFile attribute is an optional fixed_length attribute in
*the attributes table.Only located in the ClassFile struct only
*once.
*/
public final class SourceFile_attribute extends attribute_info {
publ ic int sourcefile_index;
public SourceFile_attribute(ClassFilecf,int ani,int al,int sfi){
super(cf);
attribute_name_index=ani ;
attribute_length=al;
sourcefile_index=sfi;
}
/**Used during input serialization by ClassFile only.*/
SourceFile_attribute(ClassFile cf,DataInputStream in)
throws IOException {
super(cf,in);
sourcefile_index=in.readChar();
}
/**Used during output serialization by ClassFile only.*/
void serialize(DataOutputStream out)
throws IOException{
attribute_length=2;
super.serialize(out);
out.writeChar(sourcefile_index);
}
}
A36.Synthetic_attribute.java
用于表示ClassFile内的Synthetic_attribute结构的Convience类。
import java.lang.*;
import java.io.*;
/**A synthetic attribute indicates that this class does not have
*a generated code source.It is likely to imply that the code
*is generated by machine means rather than coded directly.This
*attribute can appear in the classfile,method_infoor field_info.
*It is fixed length.
*/
public final class Synthetic_attribute extends attribute_info{
public Synthetic_attribute(ClassFile cf,int ani,int al){
super (cf);
attribute_name_index=ani;
attribute_length=al;
}
/**Used during output serialization by ClassFile only.*/
Synthetic_attribute(ClassFile cf,DataInputStream in)
throws IOException{
super(cf,in);
}
}
附件B
B1
Method<clinit>
0 new#2<Class test>
3 dup
4 invokespecial#3<Method test()>
7 putstatic#4<Field test thisTest>
10 return
B2
Method<clinit>
0 invokestatic#3<Method boolean isAlreadyLoaded()>
3 ifeq 7
6 return
7 new#5<Class test>
10 dup
11 invokespecial#6<Method test()>
14 putstatic#7<Field test thisTeSt>
17 return
B3
Method<init>
0 alOad_0
1 invokespecial#1<Method j ava.lang.Object()>
4 aload_0
5 invokestatic#2<Method long currentTimeMillis()>
8 putfield#3<Field long timestamp>
11 return
B4
Method<init>
0aload_0
1 invokespecial#1<Methodjava.lang.Object()>
4 invokestatic#2<Methodboolean isAlreadyLoaded()>
7 ifeq 11
10 return
11 aload_0
12 invokestatic#4<Method long currentTimeMillis()>
15 putfield#5<Field long timestamp>
18 return
B5
Method<clinit>
0 ldc#2<String“test”>
2 invokestatic#3<Method boolean isAlreadyLoaded(java.lang.String)>
5 ifeq 9
8 return
9 new#5<Class test>
12 dup
13 invokespecial#6<Method test()>
16 putstatic#7<Field test thisTest>
19 retum
B6
Method<init>
0 aload 0
1 invokespecial#1<Method java.lang.Object()>
4 aload_0
5 invokestatic#2<Method boolean isAlreadyLoaded(java.lang.Object)>
8 ifeq 12
11 return
12 aload_0
13 invokestatic#4<Method long currentTimeMillis()>
16 putfield#5<Field long timestamp>
19 return
附件B7
该摘录是InitClient的源代码,其针对相关类或对象的初始化状态来查询
“initialisation server”。
import java.lang.*;
import j ava.util.*;
import java.net.*;
import java.io.*;
public class InitClient{
/**Protocol specific values.*/
public final static int CLOSE=-1;
public final static int NACK=0;
public final static int ACK=1;
public final static int INITIALIZE_CLASS=10;
public final static int INITIALIZE_OBJECT=2o;
/**Initserver network values.*/
public final static String serverAddress=
System.getProperty (″InitServer_network_address″);
public final static int serverPort=
Integer.parseInt(System.getProperty(″InitServer_network_port″));
/**Table of globalID′s for local objects.(hashcode-to-globalID
mappings)*/
public final static Hashtable hashCodeToGlobalID=new Hashtable();
/**Called when a object is being initialized.*/
public static boolean isAlreadyLoaded(Object o){
//First of all,we need to resolve the globalID
//for obj ect ′o′.To do this we use the hashCodeToGlobalID
//table.
intglobalID=((Integer)hashCodeToGlobalID.get(o)).intValue();
try{
//Next,we want to connect to theInitServer,which will inform us
//of the initialization statusof this obj ect.
Socket socket=new Socket(serverAddress,serverPort);
DataOutputStream out=
new DataOutputStream(socket.getOutputStream());
DataInputStream in=
new DataInputStream(socket.getInputStream());
//Ok,now send the serialized requestto theInitServer.
out.writeInt(INITIALIZE_OBJECT);
out.writeInt(globalID);
out.flush();
//Now waitfor the reply.
int status=in.readInt(); //This is a blocking call.So we
//will wait untilthe remote side
//sends something.
if (status==NACK){
throw new AssertionError(
″Negative acknowledgement.Request failed.″);
}else if(status !=ACK){
throw new AssertionError (″Unknownacknowledgement:″
+status+″.Request failed.″);
}
//Next,read in a 32bit argument which is the count of previous
//initializations.
int count=in.readInt();
//Ifthe count is equal to 0,then this is the first
//initialization,and hence isAlreadyLoaded should be false.
//If however,the countis greater than 0,then this is already
//initialized,andthus isAlreadyLoaded should be true.
boolean isAlreadyLoaded=(count==0?false :true);
//Close down the connection.
out.writeInt(CLOSE);
out.flush();
out.close();
in.close();
socket.close(); //Make sure to close the socket.
//Return the value of the isAlreadyLoaded variable.
return isAlreadyLoaded;
}catch (IOException e){
throw new AssertionError(″Exception:″+e.toString());
}
}
/**Called when a class is being initialized.*/
public static boolean isAlreadyLoaded(String name){
try(
//First of all,we wantto connect to theInitServer,which will
//inforn us of the initialization status of this class.
Socket socket=new Socket(serverAddress,serverPort);
DataOutputStream out=
new DataOutputStream(socket.getOutputStream());
DataInputStream in=
new DataInputStream(socket.getInputStream());
//Ok,now send the serialized request to the InitServer.
out.writeInt(INITIALIZE_CLASS);
out.writeInt(name.length()); //A 32bit length argumentof
//the String name.
out.write (name.getBytes(),0,name.length()); //The byte-
//encoded
//String name.
out.flush();
//Now wait forthe reply.
int status=in.readInt(); //This is a blocking call.So we
//will waituntil the remote side
//sends something.
if (status==NACK){
throw new AssertionError{
″Negative acknowledgement.Request failed.″);
)else if (status !=ACK){
throw new AssertionError(″Unknown acknowledgement:″
+status+″.Request failed.″);
}
//Next,read in a 32bit argumentwhich is the count of the
//previous intializations.
int count=in.readInt();
//Ifthe count is equalto 0,then this is the first
//initialization,and hence isAlreadyLoaded should be false.
//If however,the countis greater than 0,then this is already
//loaded,and thus isAlreadyLoaded should be true.
boolean isAlreadyLoaded=(count ==0?false:true};
//Close downthe connection.
out.writeInt(CLOSE);
out.flush();
out.close();
in.close();
socket.close();//Make sure toclose the socket.
//Return the value of the isAlreadyLoaded variable.
return isAlreadyLoaded;
}catch (IOException e ){
throw new AssertionError(″Exception:″+e.toString());
}
}}
附件B8
该摘录是InitServer的源代码,其接收InitClient的初始化状态查询,并作出响应将对应的状态返回。
import java.lang.*;
import java.util.*;
import java.net.*;
import java.io.*;
public class InitServer implements Runnable{
/**Protocol specific values*/
public final static int CLOSE=-1;
public final static int NACK=0;
public final static int ACK=1;
public final static intINITIALIZE_CLASS=10;
public final static intINITIALIZE_OBJECT=20;
/**InitServer network values.*/
public final static intserverPort=20001;
/**Table of initialization records.*/
public final static Hashtable initializations=new Hashtable();
/**Private input/output objects.*/
private Socket socket=null ;
private DataOutputStream outputStream;
private DataInputStream inputStream;
private String address;
public static void main(String[]s)
throws Exception{
System.out.println(″InitServer_network_address=″
+InetAddress.getLocalHost().getHostAddress ());
System.out.println(″InitServer_network_port=″+serverPort);
//Create a serversocket to accept incoming initialization operation
//connections.
ServerSocket serverSocket=new ServerSocket(serverPort);
while(!Thread.interrupted()){
//Block untilan incoming initialization operation connection.
Socket socket =serverSocket.accept();
//Create a new instance of Initserver to manage this
//initialization operation connection.
new Thread(new InitServer(socket)).start();
}
}
/**Const ructor.Initialize this newInitServer instancewith necessary
resources for operation.*/
public InitServer(Socket s){
socket=s;
try{
outputStream =new DataOutputStream(s.getOutputStream());
inputStream=new DataInputStream(s.getInputStream());
address=s.getInetAddress().getHostAddress();
}catch (IOException e){
throw new AssertionError(″Exception:″+e.toString());
}
}
/**Main code body.Decode incoming initialization operation requests and
execute accordingly.*/
public void run(){
try{
//All commands are implemented as 32bit integers.
//Legal commands are listedin the ″protocol specific values″
//fields above.
int command=inputStream.readInt();
//Continue processing commands until aCLOSE operation.
while (command !=CLOSE){
if (command==INITIALIZE_CLASS){ //This is an
//INITIALIZE_CLASS
//operation.
//Read in a 32bit length field′l′,and a String name for
//this class of length ′l′.
int length=inputStream.readInt ();
byte[]b=new byte[length];
inputStream.read(b,0,b.length);
String className=new String(b,0,length);
//Synchronize on the initializations table in order to
//ensure thread-safety.
synchronized (initializations){
//Locate the previous initializations entry for this
//class,if any.
Integer entry=(Integer)initializations.get(className);
if (entry==null){ //This is an unknown class so
//update the table with a
//corresponding entry.
initializations.put(className,newInteger(1));
//send a positive acknowledgementtoInitClient,
//together with the count of previous initializations
//of this class -which in this case of an unknown
//class must be 0.
outputStream.writeInt(ACK);
outputStream.writeInt(0);
outputStream.flush();
}else( //This is a known class,so update
//the count of initializations.
initializations.put(className,
new Integer(entry.intValue()+1));
//Send a positive acknowledgement to InitClient,
//together with the count of previous initializtions
//of this class -which in this case of a known class
//must be the value of″entry.intValue()″.
outputStream.writeInt(ACK);
outputStream.writeInt(entry.intValue());
outputStream.flush();
}
}
}else if (command==INITIALIZE_OBJECT){ //This is an
//INITIALIZE OBJECT
//operation.
//Read in the globalID of the object to be initialized.
int globalID=inputStream.readInt();
//Synchronize on the initializations table in order to
//ensure thread-safety.
synchronized (initializations){
//Locate the previous initializations entry for this
//obj ect,if any.
Integer entry=(Integer)initializations.get(
newInteger(globalID));
if (entry==null){//This is an unknown objectso
//updatethe table with a
//corresponding entry.
initializations.put(new Integer(globalID),
newInteger(1));
//Send a positive acknowledgement to InitClient,
//together with the count of previous initializations
//of this object-which in this case of an unknown
//object must be 0.
outputStream.writeInt(ACK);
outputStream.writeInt(0);
outputStream.flush();
}else{ //This is a known object so update the
//countof initializations.
initializations.put(newInteger(qlobalID},
newInteger(entry.intValue()+1));
//Send a positive acknowledgementto InitClient,
//together with the countof previous initializations
//of this object-which in this case of a known
//object must be value″entry.intValue()″.
outputStream.writeInt(ACK);
outputStream.writeInt(entry.intValue());
outputStream.flush();
}
}
} else{//Unknown command.
throw new AssertionError(
″Unknown command.Operation failed.″);
}
//Read inthe nextcommand.
command =inputStream.readInt();
}
}catch (Exception e){
throw new AssertionError(″Exception:″+e.toString());
}finally{
try{
//Closing down.Cleanup this connection.
outputStream.flush();
outputStream.close();
inputStream.close();
socket.close();
}catch(Throwable t){
t.printStackTrace ();
}
//Garbage these references.
outputStream=null;
inputStream=null;
socket=null;
}
}
}
附件B9
该摘录是附件B的示例之前/之后所使用的示例应用的源代码。
import java.lang.*;
public class example{
/**Shared static field.*/
public static example currentExample;
/**Shared instance field.*/
public long timestamp;
/**Static intializer.(clinit)*/
static{
currentExample=new example();
}
/**Instance intializer (init)*/
public example (){
timestamp=System.currentTimeMillis ();
}
}
附件B10
InitLoader.java
该摘录是InitLoader的源代码,其在加载应用时对其进行修改。
import java.lang.*;
import java.io.*;
import java.net.*;
public class InitLoader extends URLClassLoader{
public InitLoader(URL[]urls){
super(urls);
}
protected Class findClass(String name)
throws ClassNotFoundException{
ClassFile cf=null;
try{
BufferedInputStream in=new
BufferedInputStream(findResource(name.replace(′.′,
′/′).concat(″.class″)).openStream());
cf=new ClassFile(in);
}catch (Exception e){throw new ClassNotFoundException(e.toString());}
for (int i=0;i<cf.methods_count;i++){
//Find the<clinit>method_info struct.
String methodName=cf.constant_pool[
cf.methods[i].name_index].toString();
if(!methodName.equals(″<clinit>″)){
continue;
}
//Now find the Code_attribute for the<clinit>method.
for (intj=0;j<cf.methods[i].attributes_count;j++){
if(!(cf.methods[i].attributes[j]instanceof Code_attribute))
continue;
Code_attribute ca =(Code_attribute)cf.methods[i].attributes[j];
//First,shift the code[]down by 4instructions.
byte[][]code2=new byte[ca.code.length+4][];
System.arraycopy(ca.code,0,code2,4,ca.code.length);
ca.code=code2;
//Then enlarge the constant_pool by 7 items.
cp_info[]cpi=new cp_info[cf.constant_pool.length+7];
System.arraycopy(cf.constant_pool,0,cpi,0,
cf.constant_pool.length);
cf.constant_pool=cpi ;
cf.constant_pool_count +=7;
//Now add the constant pool items for these instructions,
starting
//with String.
CONSTANT_String_info csi=new CONSTANT_String_info(
((CONSTANT_Class_info)cf.constant_pool[cf.this_class]).name_index);
cf.constant_pool[cf.constant_pool.length-7]=csi;
//Now addthe UTF for class.
CONSTANT_Utf8_info_u1=new CONSTANT_Utf8_info(″InitClient″);
cf.constant_pool[cf.constant_pool.length-6]=u1;
//Now add the CLAsS for the previous UTF.
CONSTANT_Class_info c1=
new CONSTANT_Class_info(cf.constant_pool.lenqth-6);
cf.constant_pool [cf.constant_pool.length-5]=c1;
//Next add the first UTF for NameAndType.
u1=new CONSTANT_Utf8_info(″isAlreadyLoaded″);
cf.constant_pool[cf.constant_pool.length-4]=u1;
//Nextadd the second UTF for NameAndType.
u1=new CONsTANT_Utf8_info(″(Lj ava/lang/string;)Z″);
cf.constant_pool[cf.constant_pool.length-3]=u1;
//Next add the NameAndType for the previous two UTFs.
CONSTANT_NameAndType_info n1=new CONSTANT_NameAndType_info(
cf.constant_pool.length-4,cf.constant_pool.length-3);
cf.constant_pool[cf.constant_pool.length-2]=n1;
//Next add the Methodref for the previous CLASS and NameAndType.
CONSTANT_Methodref_info m1=new CONSTANT_Methodref_info{
cf.constant_pool.length-5,cf.constant_pool.length-2);
cf.constant_pool[cf.constant_pool.length-1]=m1;
//Now with that done,add the instructions into the code,
starting
//with LDC.
ca.code[0]=new byte[3];
ca.code[0][0]=(byte)19;
ca.code[0][1]=(byte)(((cf.constant_pool.length-7)>>8)&
0xff);
ca.code[0][2]=(byte)((cf.constant_pool.length-7)&0xff);
//Now Add the INVOKESTATIC instruction.
ca.code[1]=new byte[3];
ca.code[1][0]=(byte)184;
ca.code[1][1]=(byte)(((cf.constant_pool.length-1)>>8)&
0xff);
ca.code[1][2]=(byte)((cf.constant_pool.length-1)&0xff);
//Next add theIFEQ instruction.
ca.code[2]=new byte[3];
ca.code[2][0]=(byte)153;
ca.code[2][1]=(byte)((4>>8)&0xff);
ca.code[2][2]=(byte)(4&0xff);
//Finally,add the RETURN instruction.
ca.code[3]=new byte[1];
ca.code[3][0]=(byte)177;
//Lastly,increment the CODE LENGTH and ATTRIBUTE LENGTH values.
ca.code_length+=10;
ca.attribute_length+=10;
}
}
try{
ByteArrayOutputStream out=newByteArrayOutputStream();
cf.serialize(out);
byte[]b=out.toByteArray();
return defineClass(name ,b,0,b.length);
}catch (Exception e){
e.printStackTrace ();
throw new ClassNotFoundException(name);
}
}
}
附件C
C1.用于单个机器的典型现有技术的终结化:
Method finalize()
0 getstatic#9<Field java.io.PrintStream out>
3 ldc#24<String″Deleted...″>
5 invokevirtual#16<Method void println(javaa.lang.String)>
8 return
C2.用于多个机器的优选终结化:
Method finalize()
0 invokestatic #3 <Method boolean isLastReference()>
3 ifne 7
6 return
7 getstatie#9<Field java.io.PrintStream out>
10 ldc#24<String″Deleted...″>
12 invokevirtual#16<Method void println(java.lang.String)>
15 return
C3.用于多个机器的优选终结化(可替换的)
Method finalize()
0 aload_0
1 invokestatic#3<Method boolean isLastReference(java.lang.Object)>
4 ifne 8
7 return
8 getstatic#9<Field java.io.PrintStream out>
11 ldc#24<String″Deleted...″>
13 invokevirtual#16<Method void println(jaava.lang.String)>
附件C4
import java.lang.*;
public class example{
/**Finalize method.*/
protected void finalize()throws Throwable{
//″Deleted...″is printed out when this obj ect is garbaged.
System.out.println(″Deleted...″);
}
}
附件C5
import java.lang.*;
import java.util.*;
import java.net.*;
import java.io.*;
public class FinalClient {
/**Protocol specific values.*/
public final static int CLOSE=-1;
public final static int NACK=0;
public final static int ACK=1;
public final static int FINALIZE_OBJECT=10;
/**Finalserver network values.*/
public final static String serverAddress=
System.getProperty(″FinalServer_network_address″);
public final static int serverPort=
Integer.parseInt (System.getProperty(″FinalServer_network_port″));
/**Table of globalID′s for local objects.(hashcode-to-globalID
mappings)*/
public final static Hashtable hashCodeToGlobalID=new Hashtable();
/**Called when a object is being finalized.*/
public staticboolean isLastReference(Obj ecto){
//First of all,we need to resolve the globalID for object ′o′.
//To do this we use the hashCodeToGlobalID table.
int globalID=((Integer)hashCodeToGlobalID.get(o)).intvalue();
//Next,we want to connect to the FinalServer,which will inform
//us of the finalization status of this object.
Socket socket=new Socket(serverAddress,serverPort);
DataOutputStream out=
new DataOutputStream(socket.getOutputStream());
DataInputStream in=new DataInputStream(socket.getInputStream());
//Ok,now send the serialized request to the FinalServer.
out.writeInt(FINALIZE_OBJECT);
out.writeInt(globalID);
out.flush();
//Now wait for the reply.
int status=in.readInt(); //This is a blocking call.So we
//willwait until the remote side
//sends something.
if(status==NACK){
throw new AssertionError(
″Negative acknowledgement.Request failed.″);
}else if (status !=ACK){
throw mew AssertionError(″Unknown acknowledgement:″
+status+″.Request failed.″);
}
//Next,read in a 32bit argument which is the count of the
//remaining finalizations
int count=in.readInt();
//If the count is equal to l,then this is the lastfinalization,
//and hence isLastReference should be true.
//If however,the count is greater than 1,then this is not the
//lastfinalization,and thus isLastReference should be false.
boolean isLastReference=(count==1?true :false);
//Close down the connection.
out.writeInt(CLOSE);
out.flush();
out.close();
in.close();
socket.close(); //Make sure to close the socket.
//Return the value of the isLastReference variable.
return isLastReference;
}catch (IOException e){
throw new AssertionError(″Exception:″+e.toString());
}
}
}
附件C6
import java.lang.*;
import java.util.*;
import java.net.*;
import java.io.*;
public class FinalServer implements Runnable{
/**Protocol pecific values */
public final static int CLOSE=-1;
public final static int NACK=0;
public final static int ACK=1;
public final static int FINALIZE_OBJECT=10;
/**FinalServer netwotk values.*/
public final static int serverPort=20001;
/**Table of finalizdtion records.*/
public final static Hashtable finalizations=new Hashtable();
/**Private input/outputobjects.*/
private Socket socket=null;
private DataOutputStream outputStream;
private DataInputStream inputStream;
private String address ;
public static void main(String[]s)
throws Exception{
System.out.println(″FinalServer_network_address=″
+InetAddress.getLocalHost().getHostAddress());
System.out.println(″FinalServer_network_port=″+serverPort);
//Create a serversocket to accept incoming initialization operation
//connections.
ServerSocket serverSocket=new ServerSocket(serverPort);
while (!Thread.interrupted()){
//Block until an incoming initialization operation connection.
Socket socket=serverSocket.accept();
//Create a new instance ofInitServerto manage this
//initialization operation connection.
new Thread(new FinalServer (socket)).start();
}
}
/**Constructor.Initialize this new FinalServer instance with necessary
resources for operation.*/
public Final Server(Socket s){
socket=s;
try{
outputStream=new DataOutputStream(s.qetOutputStream());
inputStream=new DataInputStream(s.getInputStream());
address =s.getInetAddress().getHostAddress();
}catch (IoException e){
throw new AssertionError(″Exception:″+e.toString());
}
}
/**Main code body.Decode incoming finalization operation requests and
execute accordingly.*/
public void run(){
try{
//All commands are implemented as 32bitintegers.
//Legal commands are listed in the ″protocol specific values″
//fields above.
int command=inputStream.readInt();
//Continue processing commands until a CLOSE operation.
while (command !=CLOSE){
if (command==FINALIZE_OBJECT){ //This is a
//FINALIZE_OBJECT
//operation.
//Read in the globalID of the obj ect to be finalized.
int globalID=inputStream.readInt();
//Synchronize on the finalizations table in order to ensure
//thread-safety.
synchronized (finalizations){
//Locate the previous finalizations entry for this
//obj ect,if any.
Integer entry=(Integer)finalizations.get(
newInteger(globalID));
if (entry ==null){
throw new AssertionError(″Unknown object.″);
}else if(entry.intValue()<1){
throw new AssertionError(″Invalid count.″);
}else if(entry.intValue()==1){ //Count of 1means
//this is the last
//reference,hence
//remove fromtable.
finalizations.remove(newInteger(globalID));
//Send apositive acknowledgement to FinalClient,
//together with.the count of remaining references-
//which in this case is 1.
outputStream.writeInt(ACK);
outputStream.writeInt(l);
outputStream.flush();
}else{ //This is not the last remaining
//reference,as count is greater than 1.
//Decrement count by 1.
finalizations.put (new Integer(globalID),
newInteger(entry.intValue()-1));
//Send a positive acknowledgement to FinalClient,
//together with the count of remaining references to
//thisobject-which in this case of must be value
//″entry.intValue()″.
outputStream.writeInt(ACK);
outputStream.writeInt(entry.intValue());
outputStream.flush();
}
}
}else{//Unknown command.
throw new AssertionError(
″Unknown command.Operation failed.″);
}
//Read in the next command.
command=inputStream.readInt();
}
}catch (Exception e){
throw new AssertionError(″Exception:″+e.toString());
}finally{
try{
//Closing down.Cleanup this connection.
outputStream.flush();
outputStream.close();
inputStream.close();
socket.close();
}catch (Throwable t){
t.printStackTrace();
}
//Garbage these references.
outputStream=null ;
inputStream=null;
socket=null;
}
}
}
附件C7
FinalLoader.java
该摘录是FinalLoader的源代码,其在加载应用时对其进行修改。
import java.lang.*;
import java.io.*;
import java.net.*;
public class FinalLoader extendsURLClassLoader {
public FinalLoader(URL []urls){
super(urls);
}
protectedClass findClass(String name)
throws ClassNotFoundException{
ClassFile cf=null;
try{
BufferedInputStream in=
new BufferedInputStream(findResource(name.replace(′.′,
′/′).concat (″.class″)).openStream());
cf =new ClassFile(in);
}catch (Exception e){throw new ClassNotFoundException(e.toString());}
for (int i=0;i<cf.methods_count;i++){
//Find the finalize method_info struct.
String methodName =cf.constant_pool[
cf.methods[i].name_index].toString();
if (!methodName.equals(″finalize″)){
continue;
}
//Now find the Code_attribute for the finalize method.
for (int j=0;j<cf.methods[i].attributes_count;j++){
if (!(cf.methods[i].attributes[j]instanceof Code_attribute))
continue;
Code_attribute ca =(Code_attribute)cf.methods[i].attributes[j];
//First,shift the code[]down by 4instructions.
byte[][]code2=new byte[ca.code.length+4][];
System.arraycopy(ca.code,0,code2,4,ca.code.length);
ca.code =code2;
//Then enlarge the constant_pool by 6items.
cp_info[]cpi =new cp_info[cf.constant_pool.length+6];
System.arraycopy(cf.constant_pool,0,cpi,0,
cf.constant_pool.length);
cf.constant_pool =cpi;
cf.constant_pool_count +=6;
//Now add the UTF for class.
CONSTANT_Utf8_info u1=new CONSTANT_Utf8_info(″FinalClient″);
cf.constant_pool[cf.constant_pool.length-6]=u1;
//Now add the CLASS for the previous UTF.
CONSTANT_Class_info cl =
new CONSTANT_Class_info(of.constant_pool.length-6);
cf.constant_pool[cf.constant_pool.length-5]=c1;
//Next add the first UTF for NameAndType.
u1=new CONSTANT_Utf8_info(″isLastReference″);
cf.constant_pool[cf.constant_pool.length-4]=u1;
//Next add the second UTF for NameAndType.
u1=new CONSTANT_Utf8_info(″(Ljava/lang/Object;)Z″);
cf.constant_pool[cf.constant_pool.length-3]=u1;
//Next add the NameAndType for the previous two UTFs.
CONSTANT_NameAndType_info n1=new CONSTANT_NameAndType_info{
cf.constant_pool.length-4,cf.constant_pool.length-3);
cf.constant_pool[cf.constant_Pool.length-2]=n1;
//Next add the Methodref for the previous CLASS and NameAndType.
CONSTANT_Methodref_info m1=new CONSTANT_Methodref_info{
cf.constant_pool.length-5,cf.constant_pool.length-2);
cf.constant_pool[cf.constant_pool.length-1]=m1;
//Now with that done,add the instructions into the code,
starting
//with LDC.
ca.code[0]=new byte[1];
ca.code[0][0]=(byte)42;
//Now Add theINVOKESTATIC instruction.
ca.code[1]=new byte [3];
ca.code[1][0]=(byte)184;
ca.code[1][1]=(byte)(((cf.constant_pool.length-1)>>8)&
0xff);
ca.code[1][2]=(byte)((cf.constant_pool.length-1)&0xff);
//Next add the IFNE instruction.
ca.code[2]=new byte [3];
ca.code[2][0]=(byte)154;
ca.code[2][1]=(byte)((4>>8)&0xff);
ca.code[2][2]=(byte)(4&0xff);
//Finally,add the RETURN instruction.
ca.code[3]=new byte[1];
ca.code[3][0]=(byte)177;
//Lastly,increment the CODE_LENGTH and ATTRIBUTE_LENGTH values.
ca.code_length+=8;
ca.attribute_length+=8;
}
}
try{
ByteArrayOutputStream out=new ByteArrayOutputStream();
cf.serialize(out);
byte[]b=out.toByteArray();
return defineClass(name,b,0,b.length);
}catch (Exception e){
e.printStackTrace();
throw new ClassNotFoundException(name);
}
}
}
附件D1
Method void run()
0 getstatic#2<Field java.lang.ObjectLOCK>
3 dup
4 astore_1
5 monitorenter
6 getstatic #3<Field int counter>
9 iconst_1
10 iadd
11 putstatic#3<Field int counter>
14 aload_1
15 monitorexit
16 return
附件D2
Method void run()
0 getstatic#2<Field java.lang,Object LOCK>
3 dup
4 astore_1
5 dnp
6 monitorenter
7 invokestatic#23<Method void acquireLock(javaa.lang.Object)>
10 getstatic#3<Field int counter>
13 iconSt_1
14 iadd
15 putstatic#3<Field int counter>
18 aload_1
19 dup
20 invokestatic#24<Methodvoid releaseLock(java.lang.Object)>
23 monitorexit
24 return
附件D3
import java.lang.*;
publi c class example {
/**Shared static field.*/
public final static Object LOCK=new Object();
/**Shared static field.*/
public static int counter=0;
/**Example method using synchronization.This method serves to
illustrate the use of synchronization to implement thread-safe
modification of a shared memory location by potentially multiple
threads.*/
public void run(){
//First acquire the lock,otherwise any memory writes we do will be
//prone to race-conditions.
synchronized(LOCK){
//Now that we haveacqdi red the lbck,we can safely modify memory
//in a thread-safe manner.
counter++;
}
}
}
附件D4
import java.lang.*;
importjava.util.*;
import java.net.*;
import java.io.*;
public class LockClient{
/**Protocol specific values.*/
public final static int CLOSE=-1;
publicfinal static int NACK=0;
public final static intACK=1;
public final static int ACQUIRE_LOCK=10;
public final static int RELEASE_LOCK=20;
/**LockServer network values.*/
public final static String serverAddress=
System.getProperty (″LockServer_network_address″);
public final static int serverPort =
Integer.parseInt(System.getProperty(″LockServer_network_port″));
/**Table of globalID′s for localobjects.(hashcode-to-globalID
mappings)*/
public final static HashtablehashCodeToGlobalID=new Hashtable();
/**Called when an application is to acquire a lock.*/
public static void acquireLock(Objecto)[
//First of all,we needto resolve the globalID for object ′o′.
//Todo this we use the hashCodeToGlobalID table.
int globalID=((Integer)hashCodeToGlobalID.get(o)).intValue();
try{
//Next,we want to connect to the LockServer,which will grant us
//the global lock.
Socketsocket=new Socket(serverAddress,serverPort);
DataOutputStre am out =
new DataOutputStream(socket.getOutputStream());
DataInputStream in=new DataInputStream(socket.getInputStream());
//Ok,now sendthe serialized request to the lock server.
out.writeInt (ACQUIRE_LOCK);
out.writeInt(globalID);
out.flush();
//Now waitfor the reply.
int status=in.readInt(); //This is a blocking call.So we
//will wait until the remote side
//sends something.
if (status==NACK){
throw new AssertionError(
″Negative acknowledgement.Request failed.″);
}else if (status !=ACK){
throw new AssertionError(″Unknown acknowledgement:″
+status+″.Request failed.″);
}
//Close down the connection.
out.writeInt(CLOSE);
out.flush(};
out.close();
in.close();
socket.close(); //Make sure to close the socket.
//This is a good acknowledgement,thus we can return now because
//global lock is now acquired.
return;
}catch (IOException e){
throw new AssertionError(″Exception:″+e.toString());
}
}
/**Called when an application is torelease a lock.*/
public static void releaseLock(Object o){
//First of all,we need to resolve the globalID for object ′o′.
//To do this we use the hashCodeToGlobalID table.
int globalID =((Integer)hashCodeToGlobalID.get(o)).intValue();
try{
//Next,we want to connect tothe LockServer,which records us as
//the owner of the global lock for object ′o′.
Socket socket=new Socket(serverAddress,serverPort);
DataOutputStream out=
new DataOutputStream (socket.getOutputStream());
DataInputStream in=new DataInputStream(socket.getInputStream());
//Ok,now send the serialized request to the lock server.
out.writeInt(RELEASE_LOCK);
out.writeInt(globalID);
out.flush();
//Now wait forthe reply.
intstatus=in.readInt(); //This is a blocking call.So we
//will wait until the remote side
//sends something.
if (status==NACK){
throw new AssertionError(
″Negative acknowledgement.Request failed.″);
}else if (status !=ACK){
throw new AssertionError(″Unknown acknowledgement:″
+status+″.Request failed.″);
}
//Close down the connection.
out.writeInt(CLOSE);
out.flush();
out.close ();
in.close();
socket.close(); //Make sure to close the socket.
//This is a good acknowledgement,return because global lock is
//now released.
return;
}catch (IOException e){
throw new AssertionError(″Exception:″+e.toString());
}
}
}
附件D5
import java.lang.*;
import java.util.*;
import java.net.*;
import java.io.*;
public class LockServer implements Runnable{
/**Protocol specific values */
public final static int CLOSE=-1;
public final static intNACK=0;
public final static intACK=1;
public final static intACQUIRE LOCK=10;
public final static int RELEASE LOCK=20;
/**LockServer network values.*/
public final static int serverPort =20001;
/**Table of lock records.*/
public final static Hashtable locks =new Hashtable();
/**Linked list of waiting LockManager objects.*/
public LockServer next =null;
/**Address of remote LockClient.*/
public final String address ;
/**Private input/output objects.*/
private Socket socket =null;
private DataOutputStream outputStream;
private DataInputStream inputStream;
public static void main(String[]s)
throws Exception{
System.out.println(″LockServer_network_address=″
+InetAddress.getLocalHost().getHostAddress());
System.out.println(″LockServer_network_port=″+serverPort);
//Create a serversocket to accept incoming lock operation
//connectiohs.
ServerSocket serverSocket=new ServerSocket(serverPort);
while (!Thread.interrupted()){
//Block until an incoming lock operation connection.
Socket socket=serverSocket.accept();
//Create anew instance of LockServer to manaqe this lock
//operation connection.
new Thread(new LockServer(socket)).start();
}
}
/**Constructor.Initialise this new LockServer instance with necessary
resources for operation.*/
public LockServe r(Sockets){
socket=s;
try{
outputStream=new DataOutputStream(s.getOutputStream());
inputStream=new DataInputStream(s.getInputStream());
address =s.getInetAddress().getHostAddress();
}catch (IOException e){
throw new AssertionError(″Exception:″+e.toString());
}
}
/**Main code body.Decode incoming lock operation requests and execute
accordingly.*/
public void run(){
try{
//All commands are implemented as 32bit integers.
//Legal commnands are listed in the ″protocol specific values″
//fields above.
int command=inputStream.readInt();
//Continue processing commands until a CLOSE operation.
while (command !=CLOSE){
if (command==ACQUIRE LOCK){ //This is an
//ACQUIRE_LOCK
//operation.
//Read in the globalID ofthe object to be locked.
int globalID=inputStream.readInt();
//Synchroni ze on the locks table inorder to ensure thread-
//safety.
synchronized (locks){
//Check for an existing owner of thi slock.
LockServer lock=(LockServer)locks.get(
newInteger(globalID));
if (lock==null){ //No-one presently owns this lock,
//so acquire it.
locks.put(newInteger(globalID),this);
acquireLock(); //Signal to the client the
//successful acquisition of this
//lock.
}else{ //Already owned.Append ourselves
//to end of queue.
//Search for the end of the queue.(Implemented as
//linked-list)
while (lock.next !=null){
lock=lock.next;
}
lock.next=this;//Append this lock request at end.
}
}
}else if (command==RELEASE_LOCK){//This is a
//RELEASE_LOCK
//operation.
//Read in the globalID of the obj ect to be locked.
intglobalID=inputStream.readInt();
//Synchronize on the locks table in order to ensure thread-
//safety.
synchronized (locks){
//Check to make sure we arethe owner of this lock.
LockServer lock=(LockServer)locks.get{
new Integer(globalID));
if (lock==null){
throw new AssertionError(″Unlocked.Release failed.″);
}else if (lock.address !=this.address){
throw new AssertionError(″Trying to release a lock″
+″whichthis client doesn′town.Release ″
+″failed.″);
}
lock=lock.next;
lock.acquireLock(); //Signal to the client the
//successful acquisition of this
//lock.
//Shift the linked list of pending acquisitions forward
//by one.
locks.put(newInteger(globalID),lock);
//Clear stale reference.
next=null;
}
releaseLock(); //Signal tothe client the successful
//release of this lock.
}else{ //Unknown command.
throw new AssertionError(
″Unknown command.Operation failed.″);
}
//Read in the next command.
command=inputStream.readInt();
}
}catch (Exception e){
throw new AssertionError(″Exception:″+e.toString());
}finally{
try{
//Closing down.Cleanupthis connection.
outputStream.flush();
outputStream.close();
inputStream.close();
socket.close();
}catch(Throwable t)(
t.printStackTrace();
}
// Garbage these references.
outputStream=null;
inputStream=null ;
socket=null;
}
}
/**Send a positive acknowledgement of an ACQUIRE_LOCK operation.*/
public void acquireLock()throws IOException {
outputStream.writeInt(ACK);
outputStream.flush();
}
/**Send a positive acknowledgement of a RELEASE_LOCKoperation.*/
public void releaseLock()throws IOException{
outputStream.writeInt(ACK);
outputStream.flush();
}
}
附件D6
LockLoader.java
该摘录是LockLoader的源代码,其在加载应用时对其进行修改。
import java.lang.*;
importjava.io.*;
importjava.net.*;
public class LockLoader extends URLVlassLoader{
public LockLoader(URL[]urls){
super(urls);
}
protected Class findClass(String name)
throws ClassNotFoundException{
ClassFile cf=null;
try{
BufferedInputStream in=
newBufferedInputStream(findResource(name.replace(′.′,
′/′).concat(″.class″)).openStream());
cf=new ClassFile(in);
}catch (Exception e)(throw new ClassNotFoundException(e.tostring());}
//Class-wide pointers to the enterindex and exitindex.
int enterindex=-1;
int exitindex=-1;
for (inti=0;i<cf.methods count;i++){
for (intj=0;j<cf.methods[i].attributes_count;j++){
if (!(cf.methods[i].attributes[j]instanceof Code_attribute ))
continue ;
Code_attribute ca =(Code_attribute)cf.methods[i].attributes[j];
boolean changed=false;
for (intz=0;z<ca.code.length;z++){
if((ca.code[z][0]&0xff)==194){ //Opcode for a
//MONITORENTER
//instruction.
changed =true ;
//Next,realign the code array,making room for the
//insertions.
byte[][]code2=new byte[ca.code.length+2][];
System.arraycopy(ca.code,0,code2,0,z);
code2[z+1]=ca.code[z];
System.arraycopy(ca.code,z+1,code2,z+3,
ca.code.length-(z+1));
ca.code=code2;
//Next,insert the DUP instruction.
ca.code[z]=new byte[1];
ca.code[z][0]=(byte)89;
//Finally,insertthe INVOKESTATIC instruction.
if (enterindex ==-1){
//This is the first time this class is encourtering
the
//acquirelock instruction,so have to add it to the
//constant pool.
cp_info[]cpi=new cp_info[cf.constant_pool.length+6];
System.arraycopy(cf.constant_pool,0,cpi,0,
cf.constant_pool.length);
cf.constant_pool=cpi;
cf.constant_pool_count+=6;
CONSTANT_Utf8_info u1=
new CONSTANT_Utf8_info(″LockClient″);
cf.constant_pool[cf.constant_pool.length-6]=u1;
CONSTANT_Class_info c1=new CONSTANT_Class_info{
cf.constant_pool_count-6);
cf.constant_pool[cf.constant_pool.length-5]=c1;
u1=new CONSTANT_Utf8_info(″acquireLock″);
cf.constant_pool[cf.constant_pool.length-4]=u1;
u1=new CONSTANT_Utf8_info(″(Ljava/lang/Obj ect;)V″);
cf.constant_pool[cf.constant_pool.length-3]=u1;
CONSTANT_NameAndType_info n1=
new CONSTANT_NameAndType_info{
cf.constant_pool.length-4,cf.constant_pool.length-
3);
cf.constant_pool[cf.constant_pool.length-2]=n1;
CONSTANT_Methodref_info m1=new
CONSTANT_Methodref_info (
cf.constant_pool.length-5,cf.constant_pool.length-
2);
cf.constant_pool[cf.constant_pool.length-1]=m1;
enterindex=cf.constant_pool.length-1;
}
ca.code[z+2]=new byte[3];
ca.code[z+2][0]=(byte)184;
ca.code[z+2][1]=(byte)((enterindex>>8)&0xff);
ca.code[z+2][2]=(byte)(enterindex&0xff);
//And lastly,increase the CODE_LENGTH and
ATTRIBUTE_LENGTH
//values.
ca.code_length+=4;
ca.attribute_length+=4;
z+=1;
}else if ((ca.code[z][0]&0xff)==195){ //Opcode for a
//MONITOREXIT
//instruction.
changed=true;
//Next,realign the code array,making room forthe
//insertions.
byte[][]code2=new byte[ca.code.length+2][];
System.arraycopy(ca.code,0,code2,0,z);
code2[z+1]=ca.code[z];
System.arraycopy(ca.code,z+1,code2,z+3,
ca.code.length-(z+1));
ca.code=code2;
//Next,insert the DUPinstruction.
ca.code[z]=new byte[1];
ca.code[z][0]=(byte)89;
//Finally,insert the INVOKESTATIC instruction.
if (exitindex ==-1){
//This is the first time this class is encourtering
the
//acquirelock instruction,so have to add it to the
//constant pool.
cp_info[]cpi=new cp_info[cf.constant_pool.length+6];
System.arraycopy(cf.constant_pool,0,cpi,0,
cf.constant_pool.length);
cf.constant_pool=cpi;
cf.constant_pool_count+=6;
CONSTANT Utf8_info u1=
new CONSTANT_Utf8_info(″LockClient″);
cf.constant_pool[cf.constant_pool.length-6]=u1;
CONSTANT_Class_infoc1=new CONSTANT_Class_info(
cf.constant_pool_count-6);
cf.constant_pool[cf.constant_pool.length-5]=c1;
u1=new CONSTANT_Utf8_info(″releaseLock″);
cf.constant_pool[cf.constant_pool.length-4]=u1;
u1=new CONSTANT_Utf8_info(″(Ljava/lang/Object;)V″);
cf.constant_pool[cf.constant_pool.length-3]=u1;
CONSTANT_NameAndType_info n1=
new CONSTANT_NameAndType_info{
cf.constant_pool.length-4,cf.constant_pool.length-
3);
cf.constant_pool[cf.constant_pool.length-2]=n1;
CONSTANT_Methodref_infom1=new
CONSTANT_Methodref_info(
cf.constant_pool.length-5,cf.constant_pool.length-
2);
cf.constant_pool[cf.constant_pool.length-1]=m1;
exitindex=cf.constant_pool.length-1;
}
ca.code[z+2]=new byte[3];
ca.code[z+2][0]=(byte)184;
ca.code[z+2][1]=(byte)((exitindex>>8)&0xff);
ca.code[z+2][2]=(byte)(exitindex&0xff);
//And lastly,increasethe CODE_LENGTH and
ATTRIBUTE_LENGTH
//values.
ca.code_length+=4;
ca.attribute_length+=4;
z+=1;
}
}
//If we changed this method,then increase the stack size by
one.
if (changed){
ca.max_stack++; //Just to make sure.
}
}
}
try{
ByteArrayOutputStream out=new ByteArrayOutputStream();
cf.serialize(out);
byte[]b=out.toByteArray();
return defineClass (name,b,0,b.length);
}catch (Exception e){
throw new ClassNotFoundException(name);
}
}
}
Claims (44)
1.一种多计算机***,所述多计算机***具有至少一个应用程序,所述应用程序在通过通信网络互连的多个计算机上同时运行,其中所述应用程序的不同部分基本上同时在所述多个计算机中不同的计算机上执行,其中对于每个所述部分,创建同样多个基本上相同的对象,每个所述对象在对应的计算机中,且其中每个所述计算机的所有读请求仅从读在请求计算机中创建的对象来满足。
2.如权利要求1所述的***,其中所述多个基本上相同的对象的每个具有基本上相同的名称。
3.如权利要求2所述的***,其中所述的相同命名对象的每个的初始内容是基本上相同的。
4.如权利要求2或3所述的***,其中当各个所述多个计算机都不再需要引用各个相同对象的组的其对应对象时,全体删除所述相同对象的组。
5.如权利要求4所述的***,其中每个所述计算机包括分布式运行时间装置,其中每个所述计算机的分布式运行时间装置能够与所有其他计算机通信,由此如果运行在所述计算机之一上的所述应用程序的一部分不再需要引用该计算机中的对象,则将不再引用的对象的标识由所述的一个计算机的分布式运行时间装置传送给可由所有其他计算机访问的共享表。
6.如权利要求5所述的***,其中通过***终结化例程,在加载之前、期间或之后,对每个所述应用程序进行修改,以对其中所述应用程序不再需要引用对象的每个实例进行修改。
7.如权利要求6所述的***,其中所述的所***的终结化例程修改预先存在的终结化例程,以便在所有计算机不再需要引用其对应对象时使所述预先存在的终结化例程能够执行,并在至少一个计算机确实需要引用对应对象时,禁止预先存在的终结化例程。
8.如权利要求2-4中任意一项所述的***,包括可应用于所有所述计算机的锁定装置,其中想要利用其中所命名的对象的任何计算机从所述锁定装置获取授权锁定,所述授权锁定允许所述利用,并防止所有其他计算机利用其对应的命名对象,直到所述授权锁定被放弃
9.如权利要求8所述的***,其中所述锁定装置包括获取锁定例程和释放锁定例程,且两个所述例程都包括于对运行在所有所述计算机上的所述应用程序所作的修改中。
10.如权利要求9所述的***,其中所述锁定装置进一步包括共享表,该共享表列出任何所述计算机所使用的所述命名对象、每个所述对象的锁定状态和任何未决的锁定获取的队列。
11.如权利要求10所述的***,其中所述锁定装置位于不运行所述应用程序且连接至所述通信网络的附加计算机内。
12.如权利要求11所述的***,其中通过***所述获取锁定例程和所述释放锁定例程,在加载之前、期间或之后,对每个所述应用程序进行修改,以对其中所述应用程序分别获取和释放对对象的锁定的每个实例进行修改。
13.如权利要求1-12中任意一项所述的***,其中每个所述计算机包括分布式更新装置,其中每个所述计算机的分布式更新装置能够与所有其他计算机通信,以使得如果运行在所述计算机之一上的所述应用程序的一部分改变该计算机中对象的内容,则将所述对象的内容的改变通过所述一个计算机的分布式更新装置传播到所有其他计算机,以改变每个所述其他计算机中的对应对象的内容。
14.如权利要求13所述的***,其中所有所述分布式更新装置以明显小于本地存储器读速率的数据传送速率经由所述通信链路来通信。
15.如权利要求1-14中任意一项所述的***,其中通过***更新传播例程,在加载之前、期间或之后,对每个所述应用程序进行修改,以对所述应用程序在其处写入存储器的每个实例进行修改,所述更新传播例程将一个计算机的每个存储器写传播到所有所述其他计算机。
16.如权利要求1-15中任意一项所述的***,其中通过***初始化例程,在加载之前、期间或之后,对每个所述应用程序进行修改,以对所述应用程序在其处创建对象的每个实例进行修改,所述初始化例程将一个计算机新创建的每个对象都传播到所有所述其他计算机。
17.如权利要求16所述的***,其中所述的所***的初始化例程修改预先存在的初始化例程,以便使所述预先存在的初始化例程能够在创建了所述同样多个对象的第一个对象时执行,并在创建了所述的同样多个对象的所有后续对象时,禁止所述预先存在的初始化例程。
18.如权利要求17所述的***,其中所述应用程序是根据从以下构成的过程组中所选的过程来修改的:加载时的重新编译、加载前的预编译、加载前的编译、正好适时的编译以及加载后且在应用程序的相关部分执行前的重新编译。
19.如权利要求18所述的***,其中所述被修改的应用程序根据从以下构成的组中所选的过程而被传送到所有所述计算机:主/从传送、分支传送和级联传送。
20.如权利要求1-19中任意一项所述的***,其中分配给所述应用程序或每个所述应用程序的本地存储器容量是基本上相同的,并且对所述应用程序或每个所述应用程序可用的总存储器容量是所述的所分配的存储器容量。
21.如权利要求1-20中任意一项所述的***,其中所述计算机的至少一些是由不同制造商来制造的和/或具有不同的操作***。
22.一种在多个计算机上同时运行至少一个应用程序的方法,所述计算机借助于通信网络来互连,所述方法包括以下步骤:
(i)在所述计算机中的不同计算机上执行所述应用程序的不同部分,以及对于每个所述部分,创建同样多个基本上相同的对象,所述对象每个在对应的计算机中;以及
(ii)通过仅从读在请求计算机中创建的对象来满足每个所述计算机的所有读请求。
23.如权利要求22所述的方法,进一步包括以下步骤:
(iii)以基本上相同的名称对每个所述多个基本上相同的对象命名。
24.如权利要求22或23中所述的方法,进一步包括以下步骤:
(iv)如果运行在所述计算机之一上的所述应用程序的一部分改变该计算机中对象的内容,则将所述对象的内容的改变经由所述通信网络传播到所有其他计算机,以改变每个所述其他计算机中的对应对象的内容。
25.如权利要求24中所述的方法,进一步包括以下步骤:
(v)通过***更新传播例程,在加载之前、期间或之后,对所述应用程序进行修改,以对所述应用程序在其处写入存储器的每个实例进行修改,所述更新传播例程将一个计算机的每个存储器写传播到所有所述其他计算机。
26.如权利要求25所述的方法,进一步包括以下步骤:
(vi)利用从以下构成的过程组中所选的过程来修改所述应用程序:加载时的重新编译、加载前的预编译、加载前的编译、正好适时的编译以及在加载之后且在应用程序的相关部分执行之前的重新编译。
27.如权利要求26所述的方法,进一步包括以下步骤:
(vii)利用从以下构成的组中所选的过程将所述的修改后的应用程序传送到所有所述计算机:主/从传送、分支传送和级联传送。
28.如权利要求25-27中任意一项所述的方法,进一步包括下列步骤:
(viii)以明显小于本地存储器读速率的数据传送速率来传送构成更新数据传输的所述本地存储器写。
29.如权利要求23-28中任意一项所述的方法,进一步包括下列步骤:
(ix)将所述的相同命名对象的每个的初始内容创建为基本上相同。
30.如权利要求29所述的方法,进一步包括以下步骤:
(x)如果在所述计算机之一上运行的所述应用程序的部分在该计算机中创建对象,那么所创建的对象经由所述通信网络被传播到所有其他计算机。
31.如权利要求30所述的方法,进一步包括以下步骤:
(xi)通过***初始化例程,在加载之前、期间或之后,对所述应用程序进行修改,以对所述应用程序在其处创建对象的每个实例进行修改,所述初始化例程将一个计算机创建的每个对象传播到所有所述其他计算机。
32.如权利要求31所述的方法,进一步包括以下步骤:
(xii)利用从以下所构成的过程的组中所选的过程,对所述应用程序进行修改:加载时的重新编译、加载之前的预编译、加载之前的编译、正好适时的编译以及在加载之后且在应用程序的相关部分执行之前的重新编译。
33.如权利要求32所述的方法,进一步包括以下步骤:
(xiii)利用从以下构成的组中所选的过程,将所修改的应用程序传送到所有所述计算机:主/从传送、分支传送和级联传送。
34.如权利要求22-33中任意一项所述的方法,进一步包括下列步骤:
(xiv)当所有所述多个计算机均不再需要引用其对应对象时,将所有所述的相同对象全体删除。
35.如权利要求34所述的方法,进一步包括以下步骤:
(xv)为每个所述计算机提供分布式运行时间装置,以经由所述通信网络在所述多个计算机之间进行通信。
36.如权利要求35所述的方法,进一步包括以下步骤:
(xvi)提供可由每个所述分布式运行时间装置来访问的共享表,其中存储了不再需要访问对象的任何计算机的标识连同该对象的标识。
37.如权利要求36所述的方法,进一步包括以下步骤:
(xvii)将计数器装置与所述共享表关联,所述计数器装置存储对不再需要访问所述对象的所述计算机数量的计数。
38.如权利要求37所述的方法,进一步包括以下步骤:
(xviii)提供附加的计算机,所述共享程序不在所述附加的计算机上运行,且所述附加的计算机容纳所述共享表和计数器,所述的附加的计算机连接至所述通信网络。
39.如权利要求22-34中任意一项所述的方法,进一步包括下列步骤:
(xviv)要求想要利用其中的命名对象的任何所述计算机获取授权锁定,所述授权锁定允许所述利用,且其防止所有其他计算机来利用其对应的命名对象,直到所述授权锁定被放弃。
40.如权利要求39所述的方法,进一步包括以下步骤:
(xx)为每个所述计算机提供分布式运行时间装置,以经由所述通信网络在所述多个计算机之间进行通信。
41.如权利要求40所述的方法,进一步包括以下步骤:
(xxi)提供可由每个所述分布式运行时间装置来访问的共享表,其中存储了当前需要访问对象的任何计算机的标识连同该对象的标识。
42.如权利要求41所述的方法,进一步包括以下步骤:
(xxii)将计数器装置与所述共享表关联,所述计数器装置存储对寻求访问所述对象的所述计算机数量的计数。
43.如权利要求42所述的方法,进一步包括以下步骤:
(xxiii)提供附加的计算机,所述的共享程序不在所述附加的计算机上运行,且所述附加的计算机容纳所述共享表和计数器,所述的附加的计算机连接至所述通信网络。
44.一种单个计算机,被布置为与至少一个其他同样的计算机合作以形成权利要求1至21中任意一项所述的多计算机***。
Applications Claiming Priority (2)
Application Number | Priority Date | Filing Date | Title |
---|---|---|---|
AU2004902146A AU2004902146A0 (en) | 2004-04-22 | Modified Computer Architecture | |
AU2004902146 | 2004-04-22 |
Related Parent Applications (1)
Application Number | Title | Priority Date | Filing Date |
---|---|---|---|
CN2005800184057A Division CN1965308B (zh) | 2004-04-22 | 2005-04-22 | 具有协作对象的修改后的计算机架构 |
Publications (2)
Publication Number | Publication Date |
---|---|
CN101908001A true CN101908001A (zh) | 2010-12-08 |
CN101908001B CN101908001B (zh) | 2014-05-14 |
Family
ID=35197170
Family Applications (2)
Application Number | Title | Priority Date | Filing Date |
---|---|---|---|
CN201010247309.2A Active CN101908001B (zh) | 2004-04-22 | 2005-04-22 | 多计算机*** |
CN2005800184057A Active CN1965308B (zh) | 2004-04-22 | 2005-04-22 | 具有协作对象的修改后的计算机架构 |
Family Applications After (1)
Application Number | Title | Priority Date | Filing Date |
---|---|---|---|
CN2005800184057A Active CN1965308B (zh) | 2004-04-22 | 2005-04-22 | 具有协作对象的修改后的计算机架构 |
Country Status (12)
Country | Link |
---|---|
EP (5) | EP1763774B1 (zh) |
JP (4) | JP2007534063A (zh) |
KR (1) | KR101209023B1 (zh) |
CN (2) | CN101908001B (zh) |
BR (1) | BRPI0508929A (zh) |
CA (1) | CA2563900C (zh) |
EA (1) | EA009926B1 (zh) |
IL (1) | IL178527A (zh) |
MX (1) | MXPA06012209A (zh) |
NZ (1) | NZ550480A (zh) |
WO (5) | WO2005103927A1 (zh) |
ZA (1) | ZA200608766B (zh) |
Cited By (1)
Publication number | Priority date | Publication date | Assignee | Title |
---|---|---|---|---|
CN109428812A (zh) * | 2017-09-01 | 2019-03-05 | 统专利有限责任两合公司 | 执行实时协作会话的计算机实现方法、执行实时协作会话的协作平台以及协作聊天发布对象 |
Families Citing this family (45)
Publication number | Priority date | Publication date | Assignee | Title |
---|---|---|---|---|
US7844665B2 (en) | 2004-04-23 | 2010-11-30 | Waratek Pty Ltd. | Modified computer architecture having coordinated deletion of corresponding replicated memory locations among plural computers |
US7849452B2 (en) | 2004-04-23 | 2010-12-07 | Waratek Pty Ltd. | Modification of computer applications at load time for distributed execution |
US7707179B2 (en) | 2004-04-23 | 2010-04-27 | Waratek Pty Limited | Multiple computer architecture with synchronization |
US20060265703A1 (en) | 2005-04-21 | 2006-11-23 | Holt John M | Computer architecture and method of operation for multi-computer distributed processing with replicated memory |
CN101283342B (zh) * | 2005-10-10 | 2010-09-08 | 瓦拉泰克有限公司 | 对象图的复制 |
CN101283343B (zh) * | 2005-10-10 | 2010-05-19 | 瓦拉泰克有限公司 | 具有部分存储器更新的改进的机器体系结构 |
AU2006301908B2 (en) * | 2005-10-10 | 2011-09-15 | Waratek Pty Limited | Modified machine architecture with machine redundancy |
AU2006301911B2 (en) * | 2005-10-10 | 2010-12-23 | Waratek Pty Limited | Failure resistant multiple computer system and method |
WO2007041763A1 (en) | 2005-10-10 | 2007-04-19 | Waratek Pty Limited | Multiple computer system with enhanced memory clean up |
WO2007041760A1 (en) * | 2005-10-10 | 2007-04-19 | Waratek Pty Limited | Modified machine architecture with advanced synchronization |
WO2007041761A1 (en) * | 2005-10-10 | 2007-04-19 | Waratek Pty Limited | Modified machine architecture with machine redundancy |
WO2007041764A1 (en) * | 2005-10-10 | 2007-04-19 | Waratek Pty Limited | Failure resistant multiple computer system and method |
JP2009512081A (ja) * | 2005-10-17 | 2009-03-19 | ワラテック プロプライエタリー リミテッド | オーバヘッドを低減したマルチマシーンアーキテクチャ |
US8015236B2 (en) | 2005-10-25 | 2011-09-06 | Waratek Pty. Ltd. | Replication of objects having non-primitive fields, especially addresses |
US7849369B2 (en) | 2005-10-25 | 2010-12-07 | Waratek Pty Ltd. | Failure resistant multiple computer system and method |
US7761670B2 (en) | 2005-10-25 | 2010-07-20 | Waratek Pty Limited | Modified machine architecture with advanced synchronization |
US7581069B2 (en) | 2005-10-25 | 2009-08-25 | Waratek Pty Ltd. | Multiple computer system with enhanced memory clean up |
US7958322B2 (en) | 2005-10-25 | 2011-06-07 | Waratek Pty Ltd | Multiple machine architecture with overhead reduction |
US7660960B2 (en) * | 2005-10-25 | 2010-02-09 | Waratek Pty, Ltd. | Modified machine architecture with partial memory updating |
US20080114943A1 (en) * | 2006-10-05 | 2008-05-15 | Holt John M | Adding one or more computers to a multiple computer system |
US20080140975A1 (en) * | 2006-10-05 | 2008-06-12 | Holt John M | Contention detection with data consolidation |
US20080114853A1 (en) * | 2006-10-05 | 2008-05-15 | Holt John M | Network protocol for network communications |
US20080133861A1 (en) * | 2006-10-05 | 2008-06-05 | Holt John M | Silent memory reclamation |
WO2008040067A1 (en) * | 2006-10-05 | 2008-04-10 | Waratek Pty Limited | Multiple computer with redundancy architecture |
WO2008040071A1 (en) * | 2006-10-05 | 2008-04-10 | Waratek Pty Limited | Contention detection |
US20080114896A1 (en) | 2006-10-05 | 2008-05-15 | Holt John M | Asynchronous data transmission |
US8473564B2 (en) | 2006-10-05 | 2013-06-25 | Waratek Pty Ltd. | Contention detection and resolution |
US20080133862A1 (en) * | 2006-10-05 | 2008-06-05 | Holt John M | Contention detection with modified message format |
US20080114899A1 (en) | 2006-10-05 | 2008-05-15 | Holt John M | Switch protocol for network communications |
US20080155127A1 (en) * | 2006-10-05 | 2008-06-26 | Holt John M | Multi-path switching networks |
US20080133859A1 (en) * | 2006-10-05 | 2008-06-05 | Holt John M | Advanced synchronization and contention resolution |
US20080133869A1 (en) * | 2006-10-05 | 2008-06-05 | Holt John M | Redundant multiple computer architecture |
WO2008040077A1 (en) * | 2006-10-05 | 2008-04-10 | Waratek Pty Limited | Multiple communication networks for multiple computers |
US20080133884A1 (en) * | 2006-10-05 | 2008-06-05 | Holt John M | Multiple network connections for multiple computers |
US8086805B2 (en) | 2006-10-05 | 2011-12-27 | Waratek Pty Ltd. | Advanced contention detection |
WO2008040076A1 (en) * | 2006-10-05 | 2008-04-10 | Waratek Pty Limited | Contention resolution with echo cancellation |
US20080126502A1 (en) * | 2006-10-05 | 2008-05-29 | Holt John M | Multiple computer system with dual mode redundancy architecture |
WO2008040069A1 (en) * | 2006-10-05 | 2008-04-10 | Waratek Pty Limited | Hybrid replicated shared memory |
US20080127213A1 (en) * | 2006-10-05 | 2008-05-29 | Holt John M | Contention resolution with counter rollover |
US20080126322A1 (en) * | 2006-10-05 | 2008-05-29 | Holt John M | Synchronization with partial memory replication |
US8316190B2 (en) | 2007-04-06 | 2012-11-20 | Waratek Pty. Ltd. | Computer architecture and method of operation for multi-computer distributed processing having redundant array of independent systems with replicated memory and code striping |
KR101778825B1 (ko) | 2010-05-03 | 2017-09-14 | 메르크 파텐트 게엠베하 | 제형물 및 전자 소자 |
JP5625621B2 (ja) | 2010-08-25 | 2014-11-19 | 富士通株式会社 | 検出装置、方法、及びプログラム |
CN105490908A (zh) * | 2014-09-16 | 2016-04-13 | 中兴通讯股份有限公司 | 目标资源占用情况的处理方法及装置 |
CN110069243B (zh) * | 2018-10-31 | 2023-03-03 | 上海奥陶网络科技有限公司 | 一种java程序线程优化方法 |
Citations (7)
Publication number | Priority date | Publication date | Assignee | Title |
---|---|---|---|---|
JPH01297759A (ja) * | 1988-05-26 | 1989-11-30 | Tokyo Electric Power Co Inc:The | ブロードキャストメモリ方式分散コンピュータシステム |
JPH02132543A (ja) * | 1988-11-12 | 1990-05-22 | Nec Corp | 情報処理装置 |
WO1995008809A2 (en) * | 1993-09-24 | 1995-03-30 | Oracle Corporation | Method and apparatus for data replication |
WO2002044835A2 (en) * | 2000-11-28 | 2002-06-06 | Gingerich Gregory L | A method and system for software and hardware multiplicity |
US6625751B1 (en) * | 1999-08-11 | 2003-09-23 | Sun Microsystems, Inc. | Software fault tolerant computer system |
WO2003083614A2 (en) * | 2002-03-25 | 2003-10-09 | Eternal Systems, Inc. | Transparent consistent active replication of multithreaded application programs |
US20040073828A1 (en) * | 2002-08-30 | 2004-04-15 | Vladimir Bronstein | Transparent variable state mirroring |
Family Cites Families (8)
Publication number | Priority date | Publication date | Assignee | Title |
---|---|---|---|---|
DE69131272T2 (de) * | 1990-11-13 | 1999-12-09 | International Business Machines Corp., Armonk | Paralleles Assoziativprozessor-System |
FR2691559B1 (fr) * | 1992-05-25 | 1997-01-03 | Cegelec | Systeme logiciel a objets repliques exploitant une messagerie dynamique, notamment pour installation de controle/commande a architecture redondante. |
US5960087A (en) * | 1996-07-01 | 1999-09-28 | Sun Microsystems, Inc. | Distributed garbage collection system and method |
US6072953A (en) * | 1997-09-30 | 2000-06-06 | International Business Machines Corporation | Apparatus and method for dynamically modifying class files during loading for execution |
US6324587B1 (en) * | 1997-12-23 | 2001-11-27 | Microsoft Corporation | Method, computer program product, and data structure for publishing a data object over a store and forward transport |
US6662359B1 (en) * | 2000-07-20 | 2003-12-09 | International Business Machines Corporation | System and method for injecting hooks into Java classes to handle exception and finalization processing |
JP2002116917A (ja) * | 2000-10-05 | 2002-04-19 | Fujitsu Ltd | オブジェクト指向型プログラミング言語によるソース・プログラムをコンパイルするコンパイラ |
US7774750B2 (en) * | 2005-07-19 | 2010-08-10 | Microsoft Corporation | Common concurrency runtime |
-
2005
- 2005-04-22 CN CN201010247309.2A patent/CN101908001B/zh active Active
- 2005-04-22 EP EP05733669A patent/EP1763774B1/en active Active
- 2005-04-22 EA EA200601942A patent/EA009926B1/ru not_active IP Right Cessation
- 2005-04-22 JP JP2007508674A patent/JP2007534063A/ja active Pending
- 2005-04-22 NZ NZ550480A patent/NZ550480A/en unknown
- 2005-04-22 MX MXPA06012209A patent/MXPA06012209A/es active IP Right Grant
- 2005-04-22 ZA ZA200608766A patent/ZA200608766B/xx unknown
- 2005-04-22 WO PCT/AU2005/000581 patent/WO2005103927A1/en active IP Right Grant
- 2005-04-22 JP JP2007508677A patent/JP2007534066A/ja active Pending
- 2005-04-22 JP JP2007508675A patent/JP2007534064A/ja active Pending
- 2005-04-22 CA CA2563900A patent/CA2563900C/en active Active
- 2005-04-22 JP JP2007508676A patent/JP2007534065A/ja active Pending
- 2005-04-22 EP EP05733436A patent/EP1763771A4/en not_active Withdrawn
- 2005-04-22 WO PCT/AU2005/000578 patent/WO2005103924A1/en active Application Filing
- 2005-04-22 EP EP20110002408 patent/EP2341430A1/en not_active Withdrawn
- 2005-04-22 WO PCT/AU2005/000582 patent/WO2005103928A1/en active Application Filing
- 2005-04-22 WO PCT/AU2005/000580 patent/WO2005103926A1/en active Application Filing
- 2005-04-22 EP EP05733639A patent/EP1763773A4/en not_active Withdrawn
- 2005-04-22 EP EP05733638A patent/EP1763772A4/en not_active Withdrawn
- 2005-04-22 WO PCT/AU2005/000579 patent/WO2005103925A1/en active IP Right Grant
- 2005-04-22 KR KR1020067022016A patent/KR101209023B1/ko active IP Right Grant
- 2005-04-22 BR BRPI0508929-8A patent/BRPI0508929A/pt not_active Application Discontinuation
- 2005-04-22 CN CN2005800184057A patent/CN1965308B/zh active Active
-
2006
- 2006-10-15 IL IL178527A patent/IL178527A/en active IP Right Grant
Patent Citations (7)
Publication number | Priority date | Publication date | Assignee | Title |
---|---|---|---|---|
JPH01297759A (ja) * | 1988-05-26 | 1989-11-30 | Tokyo Electric Power Co Inc:The | ブロードキャストメモリ方式分散コンピュータシステム |
JPH02132543A (ja) * | 1988-11-12 | 1990-05-22 | Nec Corp | 情報処理装置 |
WO1995008809A2 (en) * | 1993-09-24 | 1995-03-30 | Oracle Corporation | Method and apparatus for data replication |
US6625751B1 (en) * | 1999-08-11 | 2003-09-23 | Sun Microsystems, Inc. | Software fault tolerant computer system |
WO2002044835A2 (en) * | 2000-11-28 | 2002-06-06 | Gingerich Gregory L | A method and system for software and hardware multiplicity |
WO2003083614A2 (en) * | 2002-03-25 | 2003-10-09 | Eternal Systems, Inc. | Transparent consistent active replication of multithreaded application programs |
US20040073828A1 (en) * | 2002-08-30 | 2004-04-15 | Vladimir Bronstein | Transparent variable state mirroring |
Cited By (1)
Publication number | Priority date | Publication date | Assignee | Title |
---|---|---|---|---|
CN109428812A (zh) * | 2017-09-01 | 2019-03-05 | 统专利有限责任两合公司 | 执行实时协作会话的计算机实现方法、执行实时协作会话的协作平台以及协作聊天发布对象 |
Also Published As
Similar Documents
Publication | Publication Date | Title |
---|---|---|
CN1965308B (zh) | 具有协作对象的修改后的计算机架构 | |
US7844665B2 (en) | Modified computer architecture having coordinated deletion of corresponding replicated memory locations among plural computers | |
US7818296B2 (en) | Computer architecture and method of operation for multi-computer distributed processing with synchronization | |
US20060020913A1 (en) | Multiple computer architecture with synchronization | |
US20050262513A1 (en) | Modified computer architecture with initialization of objects | |
CN100587670C (zh) | 用于受控运行时环境的利用锁膨胀进行线程同步的方法和装置 | |
Turon | Reagents: expressing and composing fine-grained concurrency | |
AU2005236087B2 (en) | Modified computer architecture with coordinated objects | |
AU2005236088B2 (en) | Modified computer architecture with finalization of objects | |
AU2005236086A1 (en) | Multiple computer architecture with synchronization | |
WO2007041760A1 (en) | Modified machine architecture with advanced synchronization | |
AU2005236085A1 (en) | Modified computer architecture with initialization of objects | |
AU2005236089A1 (en) | Multiple computer architecture with replicated memory fields | |
Silaghi et al. | An MDA-based approach for inferring concurrency in distributed systems | |
Smith | Client-Server Models |
Legal Events
Date | Code | Title | Description |
---|---|---|---|
C06 | Publication | ||
PB01 | Publication | ||
C10 | Entry into substantive examination | ||
SE01 | Entry into force of request for substantive examination | ||
C14 | Grant of patent or utility model | ||
GR01 | Patent grant | ||
TR01 | Transfer of patent right | ||
TR01 | Transfer of patent right |
Effective date of registration: 20230412 Address after: Irish Dublin Patentee after: Waratek Pty Ltd. Address before: New South Wales Australia Patentee before: Waratek Pty Ltd. |