260 likes | 393 Views
第九章 运行时的存储空间. 运行时存储空间的结构和分配 过程活动记录 AR 运行时变量的访问. 运行时的存储空间结构. 要保存的信息: 目标代码;数据;库函数代码; 过程活动的控制信息等 运行时的存储空间结构:. 最大地址. 堆区空间 栈区空间. 最小地址. 库代码空间. 静态区空间. 目标代码空间. 目标程序运行时的活动. 活动: 过程的一次执行。如果 a 和 b 是两个活动,则它们的生存期或者是不重叠的,或者是嵌套的。 活动树: 由活动构成的一个树,其中 1 )树中的每个节点代表一个活动。 2 )树的根节点是程序的主过程(函数)的活动。
E N D
第九章 运行时的存储空间 • 运行时存储空间的结构和分配 • 过程活动记录AR • 运行时变量的访问
运行时的存储空间结构 • 要保存的信息: 目标代码;数据;库函数代码; 过程活动的控制信息等 • 运行时的存储空间结构: 最大地址 堆区空间 栈区空间 最小地址 库代码空间 静态区空间 目标代码空间
目标程序运行时的活动 • 活动:过程的一次执行。如果a和b是两个活动,则它们的生存期或者是不重叠的,或者是嵌套的。 • 活动树:由活动构成的一个树,其中 1)树中的每个节点代表一个活动。 2)树的根节点是程序的主过程(函数)的活动。 3)在树中若b为a的儿子节点,则必有a活动调用了b活动。 4)在树中若a为b的左兄弟节点,则必有a活动先于b活动执行。
名字的作用域和邦定 • 作用域:一个声明起作用的程序部分称为该声明的作用域。一个名字在程序中只声明一次,该名字在程序运行时也可能代表不同的数据对象。 • 环境和状态:环境表示将名字映射到存储单元的函数,状态表示将存储单元映射到它所保存的值的函数 。 • 绑定:如果环境将名字x映射到存储单元s,我们就说x被绑定(binding)到s 。
过程活动记录 • 过程活动记录(AR):过程的一个现场记录 • 记录内容: 过程控制信息:先行活动记录的动态链指针、返回地址、层数和长度等 机器状态信息:寄存器状态等 全局变量信息:非局部变量的信息 局部变量值:形参变量、局部变量和临时变量
临时变量区 局部变量区 AR的结构: 本层变量和返回值 形参变量区 返回值 变量访问信息 变量访问环境 机器状态信息 机器状态 过程层数 控制状态信息 返回地址 动态链指针 sp
抽象地址分配 I. (ℓ,off)LabelDec(ℓ,off) (ℓ,off)ConstDec(ℓ,off) (ℓ,off)TypeDec(ℓ,off) (ℓ,off)Var id:T(ℓ,off+n) (ℓ,off)ProcDec(ℓ,off) (ℓ,off)FuncDec(ℓ,off) II.(ℓ,off)Proc p()(ℓ+1,off1+ℓ+2) (ℓ,off)Func f():T(ℓ+1,off1+ℓ+2) (ℓ,off)Proc P()(ℓ,off+2) (ℓ,off)Func F():T (ℓ,off+2) III. (ℓ,off)Var ID:T(ℓ,off+1) (ℓ,off)ID:T(ℓ,off+n) IV. (ℓ,off)Proc p((ℓ+1,off0) (ℓ,off)Func f((ℓ+1,off0) (ℓ,off)Proc P((ℓ+1,off0) (ℓ,off)Fucn F((ℓ+1,off0)
抽象地址分配例子 (ℓ,10)Label 100,200; (ℓ,10)Const pai=3.14; (ℓ,10)Type arr=array[1..10]of integer; (ℓ,10)Var x:integer; (ℓ,11) a:array[1..5]of integer; (ℓ,16)Function f( (ℓ+1,4)Var x:real; (ℓ+1,5) a:arr; (ℓ+1,15)Var c:arr; (ℓ+1,16)Procedure G(); (ℓ+1,18)Function F():real (ℓ+1,20) ):real; (ℓ+1,20+ℓ+2 Begin ……end; (ℓ,16)
目标程序运行时的动作(1) 调用一个过/函时,建立新的活动记录;退出一个过/函时,删除它的当前活动记录。这些工作由目标程序来完成,分别分散在过程调用语句、过程入口和过程出口部分的目标代码中。 • 过/函调用语句所完成的工作 1)在新建立的活动记录里保存现役活动记录的始地址:0[top]:=sp; 2)在新建立的活动记录里记入先行Display表的始地址: • 实在过程语句情形:3[top]:=sp+ Noff。 • 形式过程语句情形:3[top]:=(第二形参单元)。其中第二形参单元是给形参过程名分配的第二个单元。 3)把实参信息传送到新活动记录区的形参单元中; 4)转向相应过程的目标程序。 5)如果是函数调用,则把函数值读到某寄存器中。
目标程序运行时的动作(2) • 过/函入口完成的工作 1)在新建立的活动记录里保存返回地址:1[top]:=返回地址 2)在要建立的新活动记录里生成DISPLAY表:从3[top]所指的先行DISPLAY表自底向上抄录ℓ个单元的内容(ℓ是被调用过程的层数),再添上新的sp值。 3)使新建的活动记录成为现役活动记录: sp:=top;top:=top+Moff • 过/函出口完成的工作 1)删除本层活动记录,使动态外层的活动记录成为现役活动记录: top:=sp;sp:=0[sp] 2)按1[top]中的返回地址返回。
参数传递(1) • 值调用 1)把形参当作所在过程的局部名看待,形参的存储单元在该过程的活动记录中。 2)调用过程计算实参,并把右值放入形参的存储单元中。 • 引用调用 1)如果实参是有左值的名字或表达式,则把该左值放入形参的存储单元。如果实参是a + b或2这样没有左值的表达式,则把它的值计算到新的存储单元,然后传递这个单元的地址。 2)在被调用过程的目标代码中,任何对形参的引用都是通过传给该过程的指针来间接引用实参的。
参数传递(2) • 值-结果调用 1)在控制流到被调用过程之前,由调用过程计算实参,然后将实参的右值和左值同时传给被调用过程。 2)在被调用过程中,像值调用那样使用实参的右值。 3)在被调用过程中,当控制返回调用过程时,根据传递来的实参的左值,将形参当前的值复写到实参存储单元。 • 换名调用 1)把过程当作宏来对待,也就是在调用点,用被调用过程的体来替换调用者的调用,但是形参用对应的实参文字来代替。这种文字替换方式称为宏展开或内联展开。 2)被调用过程的局部名与调用过程的名字保持区别。可以认为在宏展开前,被调用过程的每个局部名字系统地被重新命名成可区别的名字。 3)为保持实参的完整性,实参可以由括号包围
静态存储分配 • 存储对象的存储位置在程序的整个生命 周期是固定的。 • 分配对象: 全程变量 常量 信息表 • 分配方法: 块地址法:(DataArea,Offset) 变址模式:(Register,Offset)
栈式存储分配 • 存在递归调用 • 存储对象: 过程中被声明的形参、局部变量 临时变量 • 分配方法: 对每个被调用过程分配一段存储空间,sp存放当前 过程空间的开始地址;对变量X:(Level,off), 则其存放地址为off[sp]。 过程结束时自动释放空间; • 不能存储: 值的生命周期长于过程的变量; 动态申请空间的变量;
过程层数 假定主程序的层数为0,称为第0层过程。如果过程 Q是在层数为i的过程P内定义,并且P是包围Q的最小过程,那么,Q的层数就为i+1。 • 调用链 :过程名序列 若M是主程序名,则(M)是一个调用链; 若(M,…,R)是调用链,且在R中有S的调用,则(M, …, R, S)也是调用链。记为 CallChain(S)= (M, …,R, S) • 动态链: 如果有调用链CallChain(S)=(M,…,R, S), 则它对应的动态链为: DynamicChain=[AR(M),…,AR(R),AR(S)]
声明链 (M)是过程声明链;若(M,…,P)是声明链,且P中有过程Q的声明,则(M,…,P,Q)也是过程声明链。记作 DeclaChain(Q)= (M,…,P,Q) • 活跃活动记录 过程S在动态链中可有多个AR,但只有最新的AR(S)是可访问的,称其为S活跃活动记录,记为LAR(S)。 • 变量访问环境 Q的声明链中的每个过程的活跃活动记录构成的链称为Q的当前变量访问环境,记为: VarVisitEnv(LAR(Q))=[LAR(M),…, LAR(P), LAR(Q)]
变量访问环境的实现方法 • Display表方法 全局表法 局部表法 • 静态链方法 • 寄存器方法
局部Display表方法 • 对于每个AR求出其变量访问环境,并把它以 地址表的形式(Display表)保存在AR中。因 为每个AR都自带Display表,称这种方法为局 部化Display表方法。 • 如果层数为N的过程P的变量访问环境为: VarVisitEnv(AR(P))=[ARi1,…,ARi,n+1], arij表示ARij的始地址,则 [ari1,…,ari,n+1]是AR(P)的Display表.
…… [ar0,ar1,…,arN-1,newsp] Display表 …… newsp 动态链指针 …… Display表 [ar0,ar1,…,arN-1,…] …… 动态链指针 sp Display表的求法 • NewAR.Display= CurrentAR.Display的前N项newsp
AR(S) X单元 AR(M) AR(Q) AR(R) Z单元 Y单元 newsp Display 表 ar1 ar0 ar1 ar2 ar0 Off- Display sp 例:有过程M,Q,R,S,其中level(M)=0;level(Q)=1;level(R)=1;level(S)=2,各AR的Display表分别如下:
局部Display表时变量的访问 • 对一个变量X(L, off),地址为: 当L= CurrentAR.level时: addr(X)=[sp+D]+off 否则: addr(X)=CurrentAR.Display[L]+ off 即[sp+D+L]+off
静态链方法 • 原Display表部分变成一个单元,称为静态链 单元,存放静态链指针。 • 静态链指针的确定: 若NewAR.level= CurrentAR.level+1-k,则 NewAR.StaticChainPointer=Indir(sp,k) 其中Indir(sp,k)表示sp的k次间接内容。 AR(M) CurrentAR NewAR AR2 AR1 ar2 ar0 ar3 ar4 ar1 sp
使用静态链时变量的访问 • 变量X(L,off)的地址: 若L= CurrentAR.Level,则addr(X)= [sp+D]+ off 若L= CurrentAR.Level-k,则 addr(X)= Indir(sp,k)+D+ off
全局Display表和寄存器方法 • 设置一个总的Display表,其长度为最大嵌 套层数(系统确定),其中Display[i]存放 第i层最新AR的指针。D[i]表示。 • 当层数为j的过程Q被调用时: 将旧的D[j]的内容保存到NewAR(Q)中: NewAR(Q).RessumeAddr = D[j]; 改写D[j]的内容:D[j]=NewAR(Q)的地址; 当退出Q时:恢复原来D[j]的内容: D[j] = CurrentAR.ResumeAddr • 变量X(L,off)的地址:addr(X)= D[L]+off
全局Display表方法的实现 sp proc P; proc Q; begin R end proc R; proc S; begin T end proc T; begin end begin S end begin Q end 全局Display表
堆区的存储分配 • 可随时分配和释放空间 • 存储对象: 动态申请空间的变量的值 • 释放空间方法: 显式释放: 隐式释放:单指针释放 计数释放法 标记释放法 • 分配空间方法: 最佳符合法;首次优先法;循环首次优先法