9.5.2 数据结构

编译器定义了各种数据结构来抽象逃逸分析的各个概念,在详细分析处理逻辑之前,我们先看一下重要的几类:

batch

type batch struct {
    allLocs  []*location
    closures []closure

    heapLoc  location
    blankLoc location
}

batch 保存着 Batch() 函数一次逃逸分析的所有状态。其中 allLocs 代表整个数据流有向图,所有需要在堆上分配内存的变量都有一条边指向 heapLoc 顶点。

location

type location struct {
    n         ir.Node  // represented variable or expression, if any
    curfn     *ir.Func // enclosing function
    edges     []edge   // incoming edges
    loopDepth int      // loopDepth at declaration

    // resultIndex records the tuple index (starting at 1) for
    // PPARAMOUT variables within their function's result type.
    // For non-PPARAMOUT variables it's 0.
    resultIndex int

    // derefs and walkgen are used during walkOne to track the
    // minimal dereferences from the walk root.
    derefs  int // >= -1
    walkgen uint32

    // dst and dstEdgeindex track the next immediate assignment
    // destination location during walkone, along with the index
    // of the edge pointing back to this location.
    dst        *location
    dstEdgeIdx int

    // queued is used by walkAll to track whether this location is
    // in the walk queue.
    queued bool

    // escapes reports whether the represented variable's address
    // escapes; that is, whether the variable must be heap
    // allocated.
    escapes bool

    // transient reports whether the represented expression's
    // address does not outlive the statement; that is, whether
    // its storage can be immediately reused.
    transient bool

    // paramEsc records the represented parameter's leak set.
    paramEsc leaks

    captured   bool // has a closure captured this variable?
    reassigned bool // has this variable been reassigned?
    addrtaken  bool // has this variable's address been taken?
}

可以简单地将 location 理解成函数中的一个变量,但更准确地说:location 代表的是程序中需要使用的一个内存区块,例如赋值语句 c := make(chan string) 右侧并没有变量,但表达式 make(chan string) 依然需要一个 location 来表示,各种字面量的初始化表达式均是如此。

location 同时也是数据流有向图中的一个顶点(Vertex),这是逃逸分析的重要数据结构,包含的属性也比较多,其中需要特别注意的有:

  • edges: 有向图中指向本顶点的所有边

  • derefs: 该属性在逃逸分析时使用,不是前文讨论的权重

  • escapes: 标记该变量是否需要逃逸

edge

type edge struct {
    src    *location
    derefs int // >= -1
    notes  *note
}

edge 代表数据流有向图中的一条边(Edge)以及方向(Direction),属性 derefs 表示该边的权重,一条边代表程序中的一个赋值语句。其中 notes 用来记录编译器逃逸分析时的 dump 信息。

hole

type hole struct {
    dst    *location
    derefs int // >= -1
    notes  *note

    // addrtaken indicates whether this context is taking the address of
    // the expression, independent of whether the address will actually
    // be stored into a variable.
    addrtaken bool

    // uintptrEscapesHack indicates this context is evaluating an
    // argument for a //go:uintptrescapes function.
    uintptrEscapesHack bool
}

hole 封装了赋值语句中对右侧表达式的执行策略。例如对于语句 x = &p, 对应的 hole 实例的内容如下:

hole.dst: location instance of x

hole.derefs: -1

hole.addrtaken: true

除了常量运算,编译阶段并不会真正执行任何表达式,该结构体主要用来记录是对右侧表达式进行 *& 操作的情况。

note

type note struct {
    next  *note
    where ir.Node
    why   string
}

用以记录逃逸分析 dump 信息的辅助数据结构,编译日志一节所打印的内容,便是通过该数据结构记录的信息。

最后更新于