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 reflectimport ( "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 intconst ( 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个寄存器,每个寄存器的大小为sizefunc (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}}