Post on 14-Jan-2016
description
第九章 运行时的存储空间第九章 运行时的存储空间
运行时存储空间的结构和分配 过程活动记录 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 )
目标程序运行时的动作(目标程序运行时的动作( 11 ))调用一个过 / 函时,建立新的活动记录;退出一个过 /
函时,删除它的当前活动记录。这些工作由目标程序来完成,分别分散在过程调用语句、过程入口和过程出口部分的目标代码中。
过 / 函调用语句所完成的工作1 )在新建立的活动记录里保存现役活动记录的始地址:
0[top]:=sp;2 )在新建立的活动记录里记入先行 Display 表的始地址:
实在过程语句情形: 3[top]:=sp+ Noff 。 形式过程语句情形: 3[top]:=( 第二形参单元 ) 。
其中第二形参单元是给形参过程名分配的第二个单元。
3 )把实参信息传送到新活动记录区的形参单元中;4 )转向相应过程的目标程序。5 )如果是函数调用,则把函数值读到某寄存器中。
过 / 函入口完成的工作1 )在新建立的活动记录里保存返回地址: 1[top]:= 返回地址2 )在要建立的新活动记录里生成 DISPLAY 表:从 3[top] 所指
的先行 DISPLAY 表自底向上抄录ℓ个单元的内容(ℓ是被调用过程的层数),再添上新的 sp 值。
3 )使新建的活动记录成为现役活动记录:sp:=top;top:=top+Moff
过 / 函出口完成的工作1 )删除本层活动记录,使动态外层的活动记录成为现役活
动记录:top:=sp;sp:=0[sp]
2 )按 1[top] 中的返回地址返回。
目标程序运行时的动作(目标程序运行时的动作( 22 ))
参数传递(参数传递( 11 ))
值调用1 )把形参当作所在过程的局部名看待,形参的存储单元在该过程的活动记录中。2 )调用过程计算实参,并把右值放入形参的存储单元中。
引用调用 1 )如果实参是有左值的名字或表达式,则把该左值放入形参的存储单元。如果实参是 a + b 或 2 这样没有左值的表达式,则把它的值计算到新的存储单元,然后传递这个单元的地址。2 )在被调用过程的目标代码中,任何对形参的引用都是通过传给该过程的指针来间接引用实参的。
参数传递(参数传递( 22 ))值 - 结果调用
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 表方法 全局表法 局部表法 静态链方法 寄存器方法
变量访问环境的实现方法
局部局部 DisplayDisplay 表方法表方法 对于每个 AR求出其变量访问环境,并把它以 地址表的形式 (Display 表)保存在 AR 中。因 为每个 AR 都自带Display 表,称这种方法为
局 部化Display 表方法。
如果层数为 N 的过程 P 的变量访问环境为: VarVisitEnv(AR(P))=[ARi1,…,ARi,n+1],
arij 表示 ARij 的始地址,则 [ari1,…,ari,n+1] 是 AR(P) 的 Display 表 .
DisplayDisplay 表的求法表的求法 NewAR.Display= CurrentAR.Display 的前N 项 newsp
动态链指针 … … Display 表 … …
newsp
动态链指针 … …Display 表 … …
sp
[ar0,ar1,…,arN-1,…]
[ar0,ar1,…,arN-
1,newsp]
例:有过程 M,Q,R,S ,其中level(M)=0;level(Q)=1;level(R)=1;level(S)=2 ,各 AR 的 Display 表分别如下:
Z 单元
ar0
ar1
newsp
X 单元
Y 单元AR(M)
AR(Q)
AR(R)
AR(S)
ar1
ar2
ar0
sp
Display
表
Off-Display
局部局部 DisplayDisplay 表时变量的访表时变量的访问问
对一个变量 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 次间接内容。
nil
AR(M)
ar0
ar0
AR1
ar1
ar1
AR2
ar2
ar2
CurrentAR
ar3
ar?
NewAR
ar4 sp
使用静态链时变量的访问使用静态链时变量的访问
变量 X(L,off) 的地址: 若 L= CurrentAR.Level, 则 addr(X)= [sp+D]
+ off 若 L= CurrentAR.Level-k, 则 addr(X)= Indir(sp,k)+D+ off
全局全局 DisplayDisplay 表和寄存器方表和寄存器方法法
设置一个总的 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
全局全局 DisplayDisplay 表方法的实现表方法的实现
D(3)
D(2)
D(1)
AR5(T)
AR4(S)
AR3(R)
AR2(Q)
AR1(P)
sp
全局 Display 表
proc P; proc Q; begin R end proc R; proc S; begin T end proc T; begin end begin S endbegin Q end
堆区的存储分配堆区的存储分配 可随时分配和释放空间 存储对象: 动态申请空间的变量的值 释放空间方法:
显式释放: 隐式释放:单指针释放 计数释放法 标记释放法 分配空间方法: 最佳符合法;首次优先法;循环首次优先法