『compiler-5』runtime memory

运行时存储管理

一、静态存储分配

  • 静态分配概念:在编译阶段编译程序实现对存储空间的管理,为源程序中的变量分配存储
    注意:静态分配要求能够确定变量在运行时的数据空间大小,且运行时不变

  • 分配策略:无可变长的串or数组,且不允许递归调用

    1. 开辟数据区,其首地址在加载时确定
    2. 按编译顺序给每个模块分配存储空间
    3. 在模块内部按顺序给模块的变量分配存储(使用相对地址
    4. 目标地址填入变量的符号表
  • FORTRAN 子程序的数据区:一个子模块主要包括隐式参数区形式参数区局部变量和临时参数区

    • 隐式参数区:存放调用返回地址 or 不便从寄存器返回的函数返回值
    • 形式参数区:存放实参的地址或值
    • 局部变量和临时变量区:记录临时变量的存储空间

    注意:该情况下程序运行栈是由各子模块组成的,运行栈是自顶向下生长的


二、动态存储分配

  • 动态分配概念:在目标程序运行阶段目标程序实现对存储空间的管理,为源程序中的变量分配存储
    注意:动态存储分配中,要求编译程序能够生成有关存储分配的目标代码

  • 分配策略:数据区为一个

    1. 进入一个过程:在栈顶为其开辟一个数据区
    2. 退出一个过程:撤销栈顶的过程数据区
  • 活动记录:创建于运行栈上的专有数据区,包括 局部数据区参数区display

    • 局部数据区:存放本模块定义的各局部变量

    • 参数区:存放隐式参数和显式参数

      • 显式参数区:存放模块调用的各个实参值 or 实参地址
      • 隐式参数区:
        • prevabp:指向caller模块的基地址
        • ret addr(n):本模块返回到模块n
        • ret value:函数的返回值
    • display区:存放本模块的各外层模块AR的基地址abp(1 ~ i-1)

      • 变量的二维编址:(BL, ON),其中 BL 指嵌套深度、ON 指变量在本层的变量顺序号\(\ge 0\)

        内层模块可以引用外层模块的变量

      • 构造AR的display区:假设从某第 i 层模块进入某第 j 层模块,若要创建第 j 层的display区:

        • 若 j = i + 1(即 i call j 或 i begin-j-end),则有:

          j比i恰深一层

        • 若 j \(\le\) i,即从 i 跳到某个外层or同层的模块 j,则有:

          j外层的所有AR基址(1 ~ j-1)赋给i的display区

    • 运行时的变量地址计算:设要在 LEV 层访问的变量为 (BL, ON),且当前模块基址为 abp

      • 若 BL = LEV :ADDR = abp + (BL - 1) + nip + ON

        同层地址计算

      • 若 BL < LEV :ADDR = display[BL] + (BL - 1) + nip + ON

      • 若 BL \(\ge\) LEV :说明要访问内层模块的变量,不合法

        注意:(BL - 1)+nip 表示要向上跨过 display区和隐式参数区,才能到达显式参数区和局部数据
        一个AR的结构如图所示:多个AR组成了运行栈(栈的方向在图中是向上增长的)


『compiler-5』runtime memory
http://larry0454.github.io/2023/10/10/compiler/runtime-memory-management/
Author
WangLe
Posted on
October 10, 2023
Licensed under