JCVM中栈与帧的研究和设计
5 JCVM中栈与帧的结构设计
通过对JCVM中存储空间的划分,可以得到一片预留的区域(即方法执行区)用于专门实现JCVM中栈的虚拟。给这片预留的区域制定一个类似于栈先进后出的操作规则,即为虚拟的出栈。而入栈的基本单位,则为帧(Frame)。帧和方法具有一一对应的映射关系,每调用一个方法,就需要创建一个帧,并且入栈,而当方法执行完并返回值之后,相应的帧也将出栈并销毁。
帧主要用于存储数据和操作结果,返回方法的值。它主要由局部变量区、操作数栈和帧控制信息(FrameCI)组成。局部变量区主要是以1个单元,也就是2个字节作为其基本单位的局部变量数组(local variable array),而存在其中的每一个元素都是属于该方法的一个local array。其主要用来存储方法传递的参数和相关变量,是数组的结构,在字节码执行过程中,通过数组的索引值进行读写。操作数栈(operand stacks)也是以1个单元作为其基本单位,是字节码执行过程中用于临时存储中间数据和操作结构的一片预留区,根据相应方法的方法头信息确定预留空间的大小,通过执行字节码进行出入操作数栈的操作。此外,在调用方法的时候,操作数栈还负责存储传递给该方法的参数值以及存储由该方法返回的返回值。而帧的控制信息主要包括当前方法物理地址(thismethodP)、当前方法上下文(thiscontext)、调用者帧的地址(invmethodP)、调用者方法Bytecode执行进度(invbytecodenum)、调用者方法操作数栈指针(invoperandSP)。这些信息将栈中的每一个帧都动态链接起来,并起到对每个方法执行进度进行记录的作用。当前方法物理地址用于读取当前方法的Bytecode,上下文的作用相当于防火墙,用来阻止跨界的非法访问,调用者方法物理地址是在当前方法执行完成后读取调用者帧的地址,调用者方法Bytecode执行进度和操作数栈指针用于还原调用者帧的在调用前的现场。
栈与帧的结构设计如图2所示。
6 方法调用与返回操作的处理
如图2所示,每一个运行的方法对应着一个帧的结构。当一个方法需要调用另一个方法时,首先要求将被调用者方法的参数压入当前帧的操作数栈中,然后为该新方法创建一个新的帧,并入栈,将新的帧设置为当前帧。创建新帧的过程,首先是分配一个足够大小的空间给新的帧,这里,通过读取该方法的方法头,可以准确知道局部变量和操作数栈所需要的空间大小;然后初始化帧,将新方法的相关信息传入FrameCI,并对一些全局变量和指针进行修改;接着是参数的传递。在Java卡中,新方法所需要调用的参数之前已经被压入调用者方法的帧中,在不考虑叠加技术的情况下,当方法调用执行时,先将参数从调用者方法帧的操作数栈中出栈,然后在顺序进入新方法帧的局部变量区,最后根据新方法的Bytecode,执行相关操作。
对应方法结束的操作,需要销毁一个帧。这里的方法执行结果分为正常结束执行和不正常结束执行。在正常结束执行的情况下,有可能会有一个返回值给调用者方法,这时,首先将返回结果出该帧的操作数栈,通过invmethodP找到调用者帧,将调用者帧设为当前帧,再进调用者帧的操作数栈。然后修改相关全局变量和指针的值。最后回收原方法帧的使用空间,以留给下次帧的创建。若是不正常结束执行,虚拟机内将产生exception或因执行到一个抛出指令而抛出exception,这时的方法就不会有返回值返回给调用者了。
另外,之前提到的叠加技术,就是在实现JCVM时,可以将调用者方法帧操作数栈和被调用者方法帧的局部变量区进行叠加的技术,即不需要把之前压入到调用者方法帧操作数栈中的参数出操作数栈再写到被调用者方法帧的局部变量区,而是直接将调用者方法帧操作数栈的参数部分看做被调用者方法帧的局部变量区的一部分,使之实现部分区域重合。采用叠加技术不会对方法的创建和销毁产生任何影响,却能简化方法间参数传递的机制,同时有效节约方法执行区的空间。
7 帧内部数据的操作
除了方法调用需要用到的栈操作之外,事实上在JCVM中,更多的是帧内部数据的操作。这些操作主要包括对局部变量区的读写操作和对操作数栈的出入栈操作。这些操作连同调用方法的操作一起,完成整个方法的执行。
例如,有这样一个方法short add(short a,short b),其执行步骤如下:
Sload_1 //Load short from local variable 1,then push
Sload_2//oad short from local variable 2,then push
Sadd//Pop two shorts,add them,then push the result
Sstore_3//Pop,then store short into local variable 3
Sreturn//Return short from method,then destroy the Frame
当有某方法需要调用这个方法时,首先根据方法头创建帧结构,将局部变量区和操作数栈初始化,控制信息赋值,接着根据方法的执行指令对操作数栈和局部变量区进行操作。具体操作步骤如图3所示。
在上例的帧执行演示中,图3的初始化步骤是根据方法头进行空间的申请,并将相关数据进行初始化赋值。Objectref是对象引用,视具体调用方法而定,一般调用中会以参数的形式传给新的方法帧,赋值给Local variable 0,而相关参数a、b,也以参数形式在新的方法里分别赋值给Local variable 1、Local variable 2。而方法字节码的前两个指令,将存储在局部变量区索引为1、2的两个数据压入操作数栈,其后Sadd指令从操作数栈中弹出这两个数据,进行加法,再将结果压回操作数栈中。然后Sstore_3从操作数栈中弹出结果值,存储到局部变量区索引为3的位置。最后,Sreturn将该方法帧销毁,完成该方法的全过程。
通过对JCVM开发规范和一些智能卡开发公司需求和测试文档的研究和分析,本论文中所提出的存储资源管理策略,栈与帧结构的设计完全符合要求。通过利用各大公司提供的软件模拟环境和Applet应用数据包对栈与帧的设计方案进行测试,证明该方案正确可行。
JCVM中栈与帧的设计与实现是开发JCVM的核心问题。本文提出了符合JCVM开发规范的栈与帧的结构设计和执行策略,并对存储空间进行划分管理,优化了有限的智能卡存储空间,并成功使用叠加技术改进了参数传递的机制,很好地完成了JCVM中栈与帧的基本功能。本文的研究已经成功运用到华大电子股份有限公司和清华同方公司的芯片上,并已经通过相关部门的软件测试。
- 利用低成本的MCU的UART驱动智能卡(05-04)
- 非接触CPU智能卡技术(11-02)
- 使用32位MCU解决RFID智能标签/智能卡系统设计难题(10-15)
- 基于USB接口和智能卡的PKI 客户端设计(11-08)
- 利用现场总线设计电磁流量计智能卡(02-22)
- 个性消费驱动智能卡与移动支付(01-08)