# 9.5.2 数据结构

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

### batch

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

    heapLoc  location
    blankLoc location
}
```

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

### location

```go
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

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

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

### hole

```go
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 实例的内容如下：

> &#x20;hole.dst: location instance of x&#x20;
>
> hole.derefs: -1&#x20;
>
> hole.addrtaken: true

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

### note

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

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


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://gocompiler.shizhz.me/9.-golang-bian-yi-qi-tao-yi-fen-xi/9.5.2-shu-ju-jie-gou.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
