关于golang:go-reflect包中abigo

40次阅读

共计 13501 个字符,预计需要花费 34 分钟才能阅读完成。

abi 是啥具体我也不先说了,先按我的了解翻译了一遍,他就是寄存器还是堆栈调配的规约,我也是在学习,大家审慎观看哦

// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package reflect

import (
    "internal/abi"
    "internal/goexperiment"
    "unsafe"
)

// These variables are used by the register assignment
// algorithm in this file.
//
// They should be modified with care (no other reflect code
// may be executing) and are generally only modified
// when testing this package.
//
// They should never be set higher than their internal/abi
// constant counterparts, because the system relies on a
// structure that is at least large enough to hold the
// registers the system supports.
//
// Currently they're set to zero because using the actual
// constants will break every part of the toolchain that
// uses reflect to call functions (e.g. go test, or anything
// that uses text/template). The values that are currently
// commented out there should be the actual values once
// we're ready to use the register ABI everywhere.
// 这些变量都是用来作为寄存器调配算法的
var (
    intArgRegs   = abi.IntArgRegs * goexperiment.RegabiArgsInt // 整数寄存器的数量
    floatArgRegs = abi.FloatArgRegs * goexperiment.RegabiArgsInt // 浮点数寄存器的数量
    floatRegSize = uintptr(abi.EffectiveFloatRegSize * goexperiment.RegabiArgsInt) // 浮点数寄存器的宽度。可能为 0、4、8。0 代表没有,或者是通过 softfloat ABI 进行传递
)

// ABI 应用程序二进制接口。go 运行时必须恪守的编程约定。ABI 总是蕴含一系列的零碎调用和应用这些零碎调用的办法,// 以及对于程序能够应用的内存地址和应用机器寄存器的规定。// abiStep represents an ABI "instruction." Each instruction
// describes one part of how to translate between a Go value
// in memory and a call frame.
// abiStep 就是一个 ABI 指令的形容。他形容了 go 的值和函数栈帧之间的转换
type abiStep struct {
    kind abiStepKind // 分几种类型,栈传递,整数寄存器值传递,整数寄存器指针传递,浮点数寄存器传递

    // offset and size together describe a part of a Go value
    // in memory.
    // 传递值在内存中的偏移和大小
    offset uintptr
    size   uintptr // size in bytes of the part

    // These fields describe the ABI side of the translation.
    // 如果是栈传递,他的偏移地址
    stkOff uintptr // stack offset, used if kind == abiStepStack
    // 如果是整数寄存器传递(包含整数指针传递),他的索引
    ireg   int     // integer register index, used if kind == abiStepIntReg or kind == abiStepPointer
    // 如果是浮点数寄存器传递,他的索引
    freg   int     // FP register index, used if kind == abiStepFloatReg
}

// abiStepKind is the "op-code" for an abiStep instruction.
type abiStepKind int

const (
    abiStepBad      abiStepKind = iota
    abiStepStack                // copy to/from stack
    abiStepIntReg               // copy to/from integer register
    abiStepPointer              // copy pointer to/from integer register
    abiStepFloatReg             // copy to/from FP register
)

// abiSeq represents a sequence of ABI instructions for copying
// from a series of reflect.Values to a call frame (for call arguments)
// or vice-versa (for call results).
//
// An abiSeq should be populated by calling its addArg method.
// abiSeq 就是一些列 abiStep 的总和,加上了堆栈空间,和寄存器的应用
type abiSeq struct {
    // steps is the set of instructions.
    //
    // The instructions are grouped together by whole arguments,
    // with the starting index for the instructions
    // of the i'th Go value available in valueStart.
    //
    // For instance, if this abiSeq represents 3 arguments
    // passed to a function, then the 2nd argument's steps
    // begin at steps[valueStart[1]].
    //
    // Because reflect accepts Go arguments in distinct
    // Values and each Value is stored separately, each abiStep
    // that begins a new argument will have its offset
    // field == 0.
    // 这块就是理论的 ABI 形容列表,他是一组参数传递,或者是返回值传递
    steps      []abiStep
    // 这个标记了第 i 个参数或返回值的 abiStep 地位,好比以后是参数传递,要传第一个参数,那么就是 steps[valueStart[0]],以此类推
    valueStart []int

    // 栈应用空间
    stackBytes   uintptr // stack space used
    // 寄存器应用状况
    iregs, fregs int     // registers used
}

// 这个就是调试
func (a *abiSeq) dump() {
    for i, p := range a.steps {println("part", i, p.kind, p.offset, p.size, p.stkOff, p.ireg, p.freg)
    }
    print("values")
    for _, i := range a.valueStart {print(i, " ")
    }
    println()
    println("stack", a.stackBytes)
    println("iregs", a.iregs)
    println("fregs", a.fregs)
}

// stepsForValue returns the ABI instructions for translating
// the i'th Go argument or return value represented by this
// abiSeq to the Go ABI.
// stepsForValue 失去第 i 个参数产地的 ABI 指令形容序列
// 失去第 i 个参数的 ABI 指令形容序列
func (a *abiSeq) stepsForValue(i int) []abiStep {
    // s 是开始地位
    s := a.valueStart[i]
    var e int
    // a.steps 和 a.valueStart 数量不对应,反正目标是为了获取下一个参数传递形容信息的一组 ABI 序列
    if i == len(a.valueStart)-1 {e = len(a.steps)
    } else {e = a.valueStart[i+1]
    }
    return a.steps[s:e]
}

// addArg extends the abiSeq with a new Go value of type t.
//
// If the value was stack-assigned, returns the single
// abiStep describing that translation, and nil otherwise.
// 用一个新的 t 类型的值扩大 abiSeq 序列
// 如果是栈调配,就返回单个 abiStep,不然就返回 nil
// 给 seq 增加一个参数传递的 ABI 序列
func (a *abiSeq) addArg(t *rtype) *abiStep {
    // We'll always be adding a new value, so do that first.
    // 获取总长度,因为要增加的参数必定是在这个地位开始的。这个就是更新 a.valueStart 的标记
    pStart := len(a.steps)
    a.valueStart = append(a.valueStart, pStart)
    // 如果增加的类型的长度为 0
    if t.size == 0 {
        // If the size of the argument type is zero, then
        // in order to degrade gracefully into ABI0, we need
        // to stack-assign this type. The reason is that
        // although zero-sized types take up no space on the
        // stack, they do cause the next argument to be aligned.
        // So just do that here, but don't bother actually
        // generating a new ABI step for it (there's nothing to
        // actually copy).
        //
        // We cannot handle this in the recursive case of
        // regAssign because zero-sized *fields* of a
        // non-zero-sized struct do not cause it to be
        // stack-assigned. So we need a special case here
        // at the top.
        // 如果这个类型大小为 0,为了降级到 ABI0(稳固的 ABI 版本),咱们须要堆栈调配,尽管他
        // 不占据空间,但他会影响下一次内存对其,因而咱们还是须要执行此操作,但没有必要生成一个 step
        // 大小尽管为 0. 然而会影响对齐,咱们还是要对他进行肯定的解决
        // align 将 a.stackBytes 舍入为 uintptr(t.align) 的倍数,就是将 a.stackBytes 增大到增加元素的对其倍数上
        a.stackBytes = align(a.stackBytes, uintptr(t.align))
        return nil
    }
    // Hold a copy of "a" so that we can roll back if
    // register assignment fails.
    // 保留 a 的正本,不便咱们寄存器调配失败时回滚
    aOld := *a
    // 寄存器调配开始,offset=0,调配失败的话,就须要回滚,而后进行栈调配
    if !a.regAssign(t, 0) {
        // Register assignment failed. Roll back any changes
        // and stack-assign.
        *a = aOld
        // 栈调配胜利会返回最初一个步骤的 step
        a.stackAssign(t.size, uintptr(t.align))
        return &a.steps[len(a.steps)-1]
    }
    return nil
}

// addRcvr extends the abiSeq with a new method call
// receiver according to the interface calling convention.
//
// If the receiver was stack-assigned, returns the single
// abiStep describing that translation, and nil otherwise.
// Returns true if the receiver is a pointer.
// 增加一个接受者,这个是办法应用的
func (a *abiSeq) addRcvr(rcvr *rtype) (*abiStep, bool) {
    // The receiver is always one word.
    // 接受者永远是一个 word
    a.valueStart = append(a.valueStart, len(a.steps))
    var ok, ptr bool
    // 返回 rcvr 是否在接口中,并且其中是否蕴含指针,如果有指针或者是在接口中,进行寄存器传值,ptrMap 0b1,二进制的 1 代表这个是一个指针,波及到 GC 回收
    if ifaceIndir(rcvr) || rcvr.pointers() {ok = a.assignIntN(0, ptrSize, 1, 0b1)
        ptr = true
    } else {// TODO(mknyszek): Is this case even possible?
        // The interface data work never contains a non-pointer
        // value. This case was copied over from older code
        // in the reflect package which only conditionally added
        // a pointer bit to the reflect.(Value).Call stack frame's
        // GC bitmap.
        ok = a.assignIntN(0, ptrSize, 1, 0b0)
        ptr = false
    }
    if !ok {a.stackAssign(ptrSize, ptrSize)
        return &a.steps[len(a.steps)-1], ptr
    }
    return nil, ptr
}

// regAssign attempts to reserve argument registers for a value of
// type t, stored at some offset.
//
// It returns whether or not the assignment succeeded, but
// leaves any changes it made to a.steps behind, so the caller
// must undo that work by adjusting a.steps if it fails.
//
// This method along with the assign* methods represent the
// complete register-assignment algorithm for the Go ABI.
// 他将 t 类型的值保留在偏移量 offset 的地位上,这就是寄存器调配算法
func (a *abiSeq) regAssign(t *rtype, offset uintptr) bool {
    // 看 t 的 kind
    switch t.Kind() {
        // 和指针相干的整数,他们调配都是,0b1
    case UnsafePointer, Ptr, Chan, Map, Func:
        return a.assignIntN(offset, t.size, 1, 0b1)
        // 一般整数,就是 0b0
    case Bool, Int, Uint, Int8, Uint8, Int16, Uint16, Int32, Uint32, Uintptr:
        return a.assignIntN(offset, t.size, 1, 0b0)
        // 这个就是看大小辨别了,不过个别都是第二个抉择
    case Int64, Uint64:
        switch ptrSize {
        case 4:
            return a.assignIntN(offset, 4, 2, 0b0)
        case 8:
            return a.assignIntN(offset, 8, 1, 0b0)
        }
    case Float32, Float64:
        return a.assignFloatN(offset, t.size, 1)
    case Complex64:
        return a.assignFloatN(offset, 4, 2)
    case Complex128:
        return a.assignFloatN(offset, 8, 2)
    case String:
        // 字符串,整形寄存器
        return a.assignIntN(offset, ptrSize, 2, 0b01)
    case Interface:
        // interface 是 2,其余有指针都是 1,一般数据是 0
        return a.assignIntN(offset, ptrSize, 2, 0b10)
    case Slice:
        return a.assignIntN(offset, ptrSize, 3, 0b01)
    case Array:
        // 数组的话,首先先把 t 的 rtype 类型转换为 arrayType 类型,他一开始的确是 rtype,后续就是本人的类型信息
        // 相当于扩大内存了
        tt := (*arrayType)(unsafe.Pointer(t))
        // 判断 tt 的长度,如果长度为 0,不必调配,长度为 1,就调配一下,如果长度大于 1,就返回失败,通过栈调配吧
        switch tt.len {
        case 0:
            // There's nothing to assign, so don't modify
            // a.steps but succeed so the caller doesn't
            // try to stack-assign this value.
            return true
        case 1:
            return a.regAssign(tt.elem, offset)
        default:
            return false
        }
    case Struct:
        // 构造体数据,也是先映射回去,再把所有的一个一个存进去,如果有一个失败,就返回失败,里面会回滚的
        st := (*structType)(unsafe.Pointer(t))
        for i := range st.fields {f := &st.fields[i]
            if !a.regAssign(f.typ, offset+f.offset()) {return false}
        }
        return true
    default:
        print("t.Kind ==", t.Kind(), "\n")
        panic("unknown type kind")
    }
    panic("unhandled register assignment path")
}

// assignIntN assigns n values to registers, each "size" bytes large,
// from the data at [offset, offset+n*size) in memory. Each value at
// [offset+i*size, offset+(i+1)*size) for i < n is assigned to the
// next n integer registers.
//
// Bit i in ptrMap indicates whether the i'th value is a pointer.
// n must be <= 8.
//
// Returns whether assignment succeeded.
// 就是调配从 offset 开始的内存地址,调配 n 个寄存器,每个寄存器的大小为 size
func (a *abiSeq) assignIntN(offset, size uintptr, n int, ptrMap uint8) bool {
    if n > 8 || n < 0 {panic("invalid n")
    }
    // ptrMap != 0 代表着有指针,须要,并且
    if ptrMap != 0 && size != ptrSize {panic("non-empty pointer map passed for non-pointer-size values")
    }
    // a.iregs+n 是咱们以后 a 占有的寄存器数量,intArgRegs 是总数量
    if a.iregs+n > intArgRegs {return false}
    // 开始调配
    for i := 0; i < n; i++ {
        kind := abiStepIntReg
        if ptrMap&(uint8(1)<<i) != 0 {kind = abiStepPointer}
        a.steps = append(a.steps, abiStep{
            kind:   kind,
            offset: offset + uintptr(i)*size,
            size:   size,
            ireg:   a.iregs,
        })
        // 寄存器应用数量
        a.iregs++
    }
    return true
}

// assignFloatN assigns n values to registers, each "size" bytes large,
// from the data at [offset, offset+n*size) in memory. Each value at
// [offset+i*size, offset+(i+1)*size) for i < n is assigned to the
// next n floating-point registers.
//
// Returns whether assignment succeeded.
// 跟下面的差不多
func (a *abiSeq) assignFloatN(offset, size uintptr, n int) bool {
    if n < 0 {panic("invalid n")
    }
    if a.fregs+n > floatArgRegs || floatRegSize < size {return false}
    for i := 0; i < n; i++ {
        a.steps = append(a.steps, abiStep{
            kind:   abiStepFloatReg,
            offset: offset + uintptr(i)*size,
            size:   size,
            freg:   a.fregs,
        })
        a.fregs++
    }
    return true
}

// stackAssign reserves space for one value that is "size" bytes
// large with alignment "alignment" to the stack.
//
// Should not be called directly; use addArg instead.
// 栈调配,这个不应该间接调用,应该调用 addArg 或者 addRcvr
// 这个栈调配
func (a *abiSeq) stackAssign(size, alignment uintptr) {
    // 第一步内存对其
    a.stackBytes = align(a.stackBytes, alignment)
    // 增加一个形容到 abiSeq
    a.steps = append(a.steps, abiStep{
        kind:   abiStepStack,
        offset: 0, // Only used for whole arguments, so the memory offset is 0.
        size:   size,
        stkOff: a.stackBytes,
    })
    a.stackBytes += size
}

// abiDesc describes the ABI for a function or method.
// 这个才是为函数和办法定义的一组 abi 指令形容集
type abiDesc struct {
    // call and ret represent the translation steps for
    // the call and return paths of a Go function.
    // 这就是两个局部,调用传参,和返回值俩个步骤,都是 abiSeq
    call, ret abiSeq

    // These fields describe the stack space allocated
    // for the call. stackCallArgsSize is the amount of space
    // reserved for arguments but not return values. retOffset
    // is the offset at which return values begin, and
    // spill is the size in bytes of additional space reserved
    // to spill argument registers into in case of preemption in
    // reflectcall's stack frame.
    // stackCallArgsSize 参数空间大小
    // retOffset 返回值偏移地位
    // spill 额定的空间,避免参数寄存器溢出
    // 栈参数空间大小,返回值偏移地址,spill 是额定空间,和旧版的栈调配一样,为了避免寄存器放不下了,跟旧版寄存办法一样,好读取数据
    stackCallArgsSize, retOffset, spill uintptr

    // stackPtrs is a bitmap that indicates whether
    // each word in the ABI stack space (stack-assigned
    // args + return values) is a pointer. Used
    // as the heap pointer bitmap for stack space
    // passed to reflectcall.
    // 一个位图,指 ABI 参数和返回值是否是一个指针,用作栈空间反射调用堆指针空间位图
    // 与 runtime.bitvector. 统一
    stackPtrs *bitVector

    // inRegPtrs is a bitmap whose i'th bit indicates
    // whether the i'th integer argument register contains
    // a pointer. Used by makeFuncStub and methodValueCall
    // to make result pointers visible to the GC.
    //
    // outRegPtrs is the same, but for result values.
    // Used by reflectcall to make result pointers visible
    // to the GC.
    // inRegPtrs,入参 应用 makeFuncStub methodValueCall 使对 GC 可见
    // outRegPtrs,返回 应用 reflectcall 使对 GC 可见
    // 第 i 位是否蕴含指针
    // 这俩个和 GC 无关,用来裸露给 GC
    // 这个 IntArgRegBitmap 是 [(IntArgRegs + 7) / 8]uint8
    inRegPtrs, outRegPtrs abi.IntArgRegBitmap
}

func (a *abiDesc) dump() {println("ABI")
    println("call")
    a.call.dump()
    println("ret")
    a.ret.dump()
    println("stackCallArgsSize", a.stackCallArgsSize)
    println("retOffset", a.retOffset)
    println("spill", a.spill)
    print("inRegPtrs:")
    dumpPtrBitMap(a.inRegPtrs)
    println()
    print("outRegPtrs:")
    dumpPtrBitMap(a.outRegPtrs)
    println()}

func dumpPtrBitMap(b abi.IntArgRegBitmap) {
    for i := 0; i < intArgRegs; i++ {
        x := 0
        if b.Get(i) {x = 1}
        print(" ", x)
    }
}

// 封装一个参数传递过程
func newAbiDesc(t *funcType, rcvr *rtype) abiDesc {
    // We need to add space for this argument to
    // the frame so that it can spill args into it.
    //
    // The size of this space is just the sum of the sizes
    // of each register-allocated type.
    //
    // TODO(mknyszek): Remove this when we no longer have
    // caller reserved spill space.
    // 咱们须要调配一个空间,能够将参数溢出到这里
    // 这个大小只是每个寄存器调配类型的大小总和
    // 当咱们不再有调用者时删除他
    spill := uintptr(0)

    // Compute gc program & stack bitmap for stack arguments
    // 计算堆栈参数 gc 程序和堆栈位图
    stackPtrs := new(bitVector)

    // Compute the stack frame pointer bitmap and register
    // pointer bitmap for arguments.
    // 计算参数的堆栈帧指针位图和寄存器指针位图。inRegPtrs := abi.IntArgRegBitmap{}

    // Compute abiSeq for input parameters.
    // 计算入参的 seq
    var in abiSeq
    if rcvr != nil {
        // rcvr 作为第一个参数传递进去
        stkStep, isPtr := in.addRcvr(rcvr)
        if stkStep != nil {
            if isPtr {stackPtrs.append(1)
            } else {stackPtrs.append(0)
            }
        } else {spill += ptrSize}
    }
    for i, arg := range t.in() {stkStep := in.addArg(arg)
        if stkStep != nil {addTypeBits(stackPtrs, stkStep.stkOff, arg)
        } else {spill = align(spill, uintptr(arg.align))
            spill += arg.size
            for _, st := range in.stepsForValue(i) {
                if st.kind == abiStepPointer {inRegPtrs.Set(st.ireg)
                }
            }
        }
    }
    spill = align(spill, ptrSize)

    // From the input parameters alone, we now know
    // the stackCallArgsSize and retOffset.
    stackCallArgsSize := in.stackBytes
    retOffset := align(in.stackBytes, ptrSize)

    // Compute the stack frame pointer bitmap and register
    // pointer bitmap for return values.
    outRegPtrs := abi.IntArgRegBitmap{}

    // Compute abiSeq for output parameters.
    var out abiSeq
    // Stack-assigned return values do not share
    // space with arguments like they do with registers,
    // so we need to inject a stack offset here.
    // Fake it by artificially extending stackBytes by
    // the return offset.
    out.stackBytes = retOffset
    for i, res := range t.out() {stkStep := out.addArg(res)
        if stkStep != nil {addTypeBits(stackPtrs, stkStep.stkOff, res)
        } else {for _, st := range out.stepsForValue(i) {
                if st.kind == abiStepPointer {outRegPtrs.Set(st.ireg)
                }
            }
        }
    }
    // Undo the faking from earlier so that stackBytes
    // is accurate.
    out.stackBytes -= retOffset
    return abiDesc{in, out, stackCallArgsSize, retOffset, spill, stackPtrs, inRegPtrs, outRegPtrs}
}

正文完
 0