"Fossies" - the Fresh Open Source Software Archive

Member "go/src/reflect/abi.go" (26 Apr 2023, 15334 Bytes) of package /linux/misc/go1.20.4.src.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Go source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 // Copyright 2021 The Go Authors. All rights reserved.
    2 // Use of this source code is governed by a BSD-style
    3 // license that can be found in the LICENSE file.
    4 
    5 package reflect
    6 
    7 import (
    8     "internal/abi"
    9     "internal/goarch"
   10     "unsafe"
   11 )
   12 
   13 // These variables are used by the register assignment
   14 // algorithm in this file.
   15 //
   16 // They should be modified with care (no other reflect code
   17 // may be executing) and are generally only modified
   18 // when testing this package.
   19 //
   20 // They should never be set higher than their internal/abi
   21 // constant counterparts, because the system relies on a
   22 // structure that is at least large enough to hold the
   23 // registers the system supports.
   24 //
   25 // Currently they're set to zero because using the actual
   26 // constants will break every part of the toolchain that
   27 // uses reflect to call functions (e.g. go test, or anything
   28 // that uses text/template). The values that are currently
   29 // commented out there should be the actual values once
   30 // we're ready to use the register ABI everywhere.
   31 var (
   32     intArgRegs   = abi.IntArgRegs
   33     floatArgRegs = abi.FloatArgRegs
   34     floatRegSize = uintptr(abi.EffectiveFloatRegSize)
   35 )
   36 
   37 // abiStep represents an ABI "instruction." Each instruction
   38 // describes one part of how to translate between a Go value
   39 // in memory and a call frame.
   40 type abiStep struct {
   41     kind abiStepKind
   42 
   43     // offset and size together describe a part of a Go value
   44     // in memory.
   45     offset uintptr
   46     size   uintptr // size in bytes of the part
   47 
   48     // These fields describe the ABI side of the translation.
   49     stkOff uintptr // stack offset, used if kind == abiStepStack
   50     ireg   int     // integer register index, used if kind == abiStepIntReg or kind == abiStepPointer
   51     freg   int     // FP register index, used if kind == abiStepFloatReg
   52 }
   53 
   54 // abiStepKind is the "op-code" for an abiStep instruction.
   55 type abiStepKind int
   56 
   57 const (
   58     abiStepBad      abiStepKind = iota
   59     abiStepStack                // copy to/from stack
   60     abiStepIntReg               // copy to/from integer register
   61     abiStepPointer              // copy pointer to/from integer register
   62     abiStepFloatReg             // copy to/from FP register
   63 )
   64 
   65 // abiSeq represents a sequence of ABI instructions for copying
   66 // from a series of reflect.Values to a call frame (for call arguments)
   67 // or vice-versa (for call results).
   68 //
   69 // An abiSeq should be populated by calling its addArg method.
   70 type abiSeq struct {
   71     // steps is the set of instructions.
   72     //
   73     // The instructions are grouped together by whole arguments,
   74     // with the starting index for the instructions
   75     // of the i'th Go value available in valueStart.
   76     //
   77     // For instance, if this abiSeq represents 3 arguments
   78     // passed to a function, then the 2nd argument's steps
   79     // begin at steps[valueStart[1]].
   80     //
   81     // Because reflect accepts Go arguments in distinct
   82     // Values and each Value is stored separately, each abiStep
   83     // that begins a new argument will have its offset
   84     // field == 0.
   85     steps      []abiStep
   86     valueStart []int
   87 
   88     stackBytes   uintptr // stack space used
   89     iregs, fregs int     // registers used
   90 }
   91 
   92 func (a *abiSeq) dump() {
   93     for i, p := range a.steps {
   94         println("part", i, p.kind, p.offset, p.size, p.stkOff, p.ireg, p.freg)
   95     }
   96     print("values ")
   97     for _, i := range a.valueStart {
   98         print(i, " ")
   99     }
  100     println()
  101     println("stack", a.stackBytes)
  102     println("iregs", a.iregs)
  103     println("fregs", a.fregs)
  104 }
  105 
  106 // stepsForValue returns the ABI instructions for translating
  107 // the i'th Go argument or return value represented by this
  108 // abiSeq to the Go ABI.
  109 func (a *abiSeq) stepsForValue(i int) []abiStep {
  110     s := a.valueStart[i]
  111     var e int
  112     if i == len(a.valueStart)-1 {
  113         e = len(a.steps)
  114     } else {
  115         e = a.valueStart[i+1]
  116     }
  117     return a.steps[s:e]
  118 }
  119 
  120 // addArg extends the abiSeq with a new Go value of type t.
  121 //
  122 // If the value was stack-assigned, returns the single
  123 // abiStep describing that translation, and nil otherwise.
  124 func (a *abiSeq) addArg(t *rtype) *abiStep {
  125     // We'll always be adding a new value, so do that first.
  126     pStart := len(a.steps)
  127     a.valueStart = append(a.valueStart, pStart)
  128     if t.size == 0 {
  129         // If the size of the argument type is zero, then
  130         // in order to degrade gracefully into ABI0, we need
  131         // to stack-assign this type. The reason is that
  132         // although zero-sized types take up no space on the
  133         // stack, they do cause the next argument to be aligned.
  134         // So just do that here, but don't bother actually
  135         // generating a new ABI step for it (there's nothing to
  136         // actually copy).
  137         //
  138         // We cannot handle this in the recursive case of
  139         // regAssign because zero-sized *fields* of a
  140         // non-zero-sized struct do not cause it to be
  141         // stack-assigned. So we need a special case here
  142         // at the top.
  143         a.stackBytes = align(a.stackBytes, uintptr(t.align))
  144         return nil
  145     }
  146     // Hold a copy of "a" so that we can roll back if
  147     // register assignment fails.
  148     aOld := *a
  149     if !a.regAssign(t, 0) {
  150         // Register assignment failed. Roll back any changes
  151         // and stack-assign.
  152         *a = aOld
  153         a.stackAssign(t.size, uintptr(t.align))
  154         return &a.steps[len(a.steps)-1]
  155     }
  156     return nil
  157 }
  158 
  159 // addRcvr extends the abiSeq with a new method call
  160 // receiver according to the interface calling convention.
  161 //
  162 // If the receiver was stack-assigned, returns the single
  163 // abiStep describing that translation, and nil otherwise.
  164 // Returns true if the receiver is a pointer.
  165 func (a *abiSeq) addRcvr(rcvr *rtype) (*abiStep, bool) {
  166     // The receiver is always one word.
  167     a.valueStart = append(a.valueStart, len(a.steps))
  168     var ok, ptr bool
  169     if ifaceIndir(rcvr) || rcvr.pointers() {
  170         ok = a.assignIntN(0, goarch.PtrSize, 1, 0b1)
  171         ptr = true
  172     } else {
  173         // TODO(mknyszek): Is this case even possible?
  174         // The interface data work never contains a non-pointer
  175         // value. This case was copied over from older code
  176         // in the reflect package which only conditionally added
  177         // a pointer bit to the reflect.(Value).Call stack frame's
  178         // GC bitmap.
  179         ok = a.assignIntN(0, goarch.PtrSize, 1, 0b0)
  180         ptr = false
  181     }
  182     if !ok {
  183         a.stackAssign(goarch.PtrSize, goarch.PtrSize)
  184         return &a.steps[len(a.steps)-1], ptr
  185     }
  186     return nil, ptr
  187 }
  188 
  189 // regAssign attempts to reserve argument registers for a value of
  190 // type t, stored at some offset.
  191 //
  192 // It returns whether or not the assignment succeeded, but
  193 // leaves any changes it made to a.steps behind, so the caller
  194 // must undo that work by adjusting a.steps if it fails.
  195 //
  196 // This method along with the assign* methods represent the
  197 // complete register-assignment algorithm for the Go ABI.
  198 func (a *abiSeq) regAssign(t *rtype, offset uintptr) bool {
  199     switch t.Kind() {
  200     case UnsafePointer, Pointer, Chan, Map, Func:
  201         return a.assignIntN(offset, t.size, 1, 0b1)
  202     case Bool, Int, Uint, Int8, Uint8, Int16, Uint16, Int32, Uint32, Uintptr:
  203         return a.assignIntN(offset, t.size, 1, 0b0)
  204     case Int64, Uint64:
  205         switch goarch.PtrSize {
  206         case 4:
  207             return a.assignIntN(offset, 4, 2, 0b0)
  208         case 8:
  209             return a.assignIntN(offset, 8, 1, 0b0)
  210         }
  211     case Float32, Float64:
  212         return a.assignFloatN(offset, t.size, 1)
  213     case Complex64:
  214         return a.assignFloatN(offset, 4, 2)
  215     case Complex128:
  216         return a.assignFloatN(offset, 8, 2)
  217     case String:
  218         return a.assignIntN(offset, goarch.PtrSize, 2, 0b01)
  219     case Interface:
  220         return a.assignIntN(offset, goarch.PtrSize, 2, 0b10)
  221     case Slice:
  222         return a.assignIntN(offset, goarch.PtrSize, 3, 0b001)
  223     case Array:
  224         tt := (*arrayType)(unsafe.Pointer(t))
  225         switch tt.len {
  226         case 0:
  227             // There's nothing to assign, so don't modify
  228             // a.steps but succeed so the caller doesn't
  229             // try to stack-assign this value.
  230             return true
  231         case 1:
  232             return a.regAssign(tt.elem, offset)
  233         default:
  234             return false
  235         }
  236     case Struct:
  237         st := (*structType)(unsafe.Pointer(t))
  238         for i := range st.fields {
  239             f := &st.fields[i]
  240             if !a.regAssign(f.typ, offset+f.offset) {
  241                 return false
  242             }
  243         }
  244         return true
  245     default:
  246         print("t.Kind == ", t.Kind(), "\n")
  247         panic("unknown type kind")
  248     }
  249     panic("unhandled register assignment path")
  250 }
  251 
  252 // assignIntN assigns n values to registers, each "size" bytes large,
  253 // from the data at [offset, offset+n*size) in memory. Each value at
  254 // [offset+i*size, offset+(i+1)*size) for i < n is assigned to the
  255 // next n integer registers.
  256 //
  257 // Bit i in ptrMap indicates whether the i'th value is a pointer.
  258 // n must be <= 8.
  259 //
  260 // Returns whether assignment succeeded.
  261 func (a *abiSeq) assignIntN(offset, size uintptr, n int, ptrMap uint8) bool {
  262     if n > 8 || n < 0 {
  263         panic("invalid n")
  264     }
  265     if ptrMap != 0 && size != goarch.PtrSize {
  266         panic("non-empty pointer map passed for non-pointer-size values")
  267     }
  268     if a.iregs+n > intArgRegs {
  269         return false
  270     }
  271     for i := 0; i < n; i++ {
  272         kind := abiStepIntReg
  273         if ptrMap&(uint8(1)<<i) != 0 {
  274             kind = abiStepPointer
  275         }
  276         a.steps = append(a.steps, abiStep{
  277             kind:   kind,
  278             offset: offset + uintptr(i)*size,
  279             size:   size,
  280             ireg:   a.iregs,
  281         })
  282         a.iregs++
  283     }
  284     return true
  285 }
  286 
  287 // assignFloatN assigns n values to registers, each "size" bytes large,
  288 // from the data at [offset, offset+n*size) in memory. Each value at
  289 // [offset+i*size, offset+(i+1)*size) for i < n is assigned to the
  290 // next n floating-point registers.
  291 //
  292 // Returns whether assignment succeeded.
  293 func (a *abiSeq) assignFloatN(offset, size uintptr, n int) bool {
  294     if n < 0 {
  295         panic("invalid n")
  296     }
  297     if a.fregs+n > floatArgRegs || floatRegSize < size {
  298         return false
  299     }
  300     for i := 0; i < n; i++ {
  301         a.steps = append(a.steps, abiStep{
  302             kind:   abiStepFloatReg,
  303             offset: offset + uintptr(i)*size,
  304             size:   size,
  305             freg:   a.fregs,
  306         })
  307         a.fregs++
  308     }
  309     return true
  310 }
  311 
  312 // stackAssign reserves space for one value that is "size" bytes
  313 // large with alignment "alignment" to the stack.
  314 //
  315 // Should not be called directly; use addArg instead.
  316 func (a *abiSeq) stackAssign(size, alignment uintptr) {
  317     a.stackBytes = align(a.stackBytes, alignment)
  318     a.steps = append(a.steps, abiStep{
  319         kind:   abiStepStack,
  320         offset: 0, // Only used for whole arguments, so the memory offset is 0.
  321         size:   size,
  322         stkOff: a.stackBytes,
  323     })
  324     a.stackBytes += size
  325 }
  326 
  327 // abiDesc describes the ABI for a function or method.
  328 type abiDesc struct {
  329     // call and ret represent the translation steps for
  330     // the call and return paths of a Go function.
  331     call, ret abiSeq
  332 
  333     // These fields describe the stack space allocated
  334     // for the call. stackCallArgsSize is the amount of space
  335     // reserved for arguments but not return values. retOffset
  336     // is the offset at which return values begin, and
  337     // spill is the size in bytes of additional space reserved
  338     // to spill argument registers into in case of preemption in
  339     // reflectcall's stack frame.
  340     stackCallArgsSize, retOffset, spill uintptr
  341 
  342     // stackPtrs is a bitmap that indicates whether
  343     // each word in the ABI stack space (stack-assigned
  344     // args + return values) is a pointer. Used
  345     // as the heap pointer bitmap for stack space
  346     // passed to reflectcall.
  347     stackPtrs *bitVector
  348 
  349     // inRegPtrs is a bitmap whose i'th bit indicates
  350     // whether the i'th integer argument register contains
  351     // a pointer. Used by makeFuncStub and methodValueCall
  352     // to make result pointers visible to the GC.
  353     //
  354     // outRegPtrs is the same, but for result values.
  355     // Used by reflectcall to make result pointers visible
  356     // to the GC.
  357     inRegPtrs, outRegPtrs abi.IntArgRegBitmap
  358 }
  359 
  360 func (a *abiDesc) dump() {
  361     println("ABI")
  362     println("call")
  363     a.call.dump()
  364     println("ret")
  365     a.ret.dump()
  366     println("stackCallArgsSize", a.stackCallArgsSize)
  367     println("retOffset", a.retOffset)
  368     println("spill", a.spill)
  369     print("inRegPtrs:")
  370     dumpPtrBitMap(a.inRegPtrs)
  371     println()
  372     print("outRegPtrs:")
  373     dumpPtrBitMap(a.outRegPtrs)
  374     println()
  375 }
  376 
  377 func dumpPtrBitMap(b abi.IntArgRegBitmap) {
  378     for i := 0; i < intArgRegs; i++ {
  379         x := 0
  380         if b.Get(i) {
  381             x = 1
  382         }
  383         print(" ", x)
  384     }
  385 }
  386 
  387 func newAbiDesc(t *funcType, rcvr *rtype) abiDesc {
  388     // We need to add space for this argument to
  389     // the frame so that it can spill args into it.
  390     //
  391     // The size of this space is just the sum of the sizes
  392     // of each register-allocated type.
  393     //
  394     // TODO(mknyszek): Remove this when we no longer have
  395     // caller reserved spill space.
  396     spill := uintptr(0)
  397 
  398     // Compute gc program & stack bitmap for stack arguments
  399     stackPtrs := new(bitVector)
  400 
  401     // Compute the stack frame pointer bitmap and register
  402     // pointer bitmap for arguments.
  403     inRegPtrs := abi.IntArgRegBitmap{}
  404 
  405     // Compute abiSeq for input parameters.
  406     var in abiSeq
  407     if rcvr != nil {
  408         stkStep, isPtr := in.addRcvr(rcvr)
  409         if stkStep != nil {
  410             if isPtr {
  411                 stackPtrs.append(1)
  412             } else {
  413                 stackPtrs.append(0)
  414             }
  415         } else {
  416             spill += goarch.PtrSize
  417         }
  418     }
  419     for i, arg := range t.in() {
  420         stkStep := in.addArg(arg)
  421         if stkStep != nil {
  422             addTypeBits(stackPtrs, stkStep.stkOff, arg)
  423         } else {
  424             spill = align(spill, uintptr(arg.align))
  425             spill += arg.size
  426             for _, st := range in.stepsForValue(i) {
  427                 if st.kind == abiStepPointer {
  428                     inRegPtrs.Set(st.ireg)
  429                 }
  430             }
  431         }
  432     }
  433     spill = align(spill, goarch.PtrSize)
  434 
  435     // From the input parameters alone, we now know
  436     // the stackCallArgsSize and retOffset.
  437     stackCallArgsSize := in.stackBytes
  438     retOffset := align(in.stackBytes, goarch.PtrSize)
  439 
  440     // Compute the stack frame pointer bitmap and register
  441     // pointer bitmap for return values.
  442     outRegPtrs := abi.IntArgRegBitmap{}
  443 
  444     // Compute abiSeq for output parameters.
  445     var out abiSeq
  446     // Stack-assigned return values do not share
  447     // space with arguments like they do with registers,
  448     // so we need to inject a stack offset here.
  449     // Fake it by artificially extending stackBytes by
  450     // the return offset.
  451     out.stackBytes = retOffset
  452     for i, res := range t.out() {
  453         stkStep := out.addArg(res)
  454         if stkStep != nil {
  455             addTypeBits(stackPtrs, stkStep.stkOff, res)
  456         } else {
  457             for _, st := range out.stepsForValue(i) {
  458                 if st.kind == abiStepPointer {
  459                     outRegPtrs.Set(st.ireg)
  460                 }
  461             }
  462         }
  463     }
  464     // Undo the faking from earlier so that stackBytes
  465     // is accurate.
  466     out.stackBytes -= retOffset
  467     return abiDesc{in, out, stackCallArgsSize, retOffset, spill, stackPtrs, inRegPtrs, outRegPtrs}
  468 }
  469 
  470 // intFromReg loads an argSize sized integer from reg and places it at to.
  471 //
  472 // argSize must be non-zero, fit in a register, and a power-of-two.
  473 func intFromReg(r *abi.RegArgs, reg int, argSize uintptr, to unsafe.Pointer) {
  474     memmove(to, r.IntRegArgAddr(reg, argSize), argSize)
  475 }
  476 
  477 // intToReg loads an argSize sized integer and stores it into reg.
  478 //
  479 // argSize must be non-zero, fit in a register, and a power-of-two.
  480 func intToReg(r *abi.RegArgs, reg int, argSize uintptr, from unsafe.Pointer) {
  481     memmove(r.IntRegArgAddr(reg, argSize), from, argSize)
  482 }
  483 
  484 // floatFromReg loads a float value from its register representation in r.
  485 //
  486 // argSize must be 4 or 8.
  487 func floatFromReg(r *abi.RegArgs, reg int, argSize uintptr, to unsafe.Pointer) {
  488     switch argSize {
  489     case 4:
  490         *(*float32)(to) = archFloat32FromReg(r.Floats[reg])
  491     case 8:
  492         *(*float64)(to) = *(*float64)(unsafe.Pointer(&r.Floats[reg]))
  493     default:
  494         panic("bad argSize")
  495     }
  496 }
  497 
  498 // floatToReg stores a float value in its register representation in r.
  499 //
  500 // argSize must be either 4 or 8.
  501 func floatToReg(r *abi.RegArgs, reg int, argSize uintptr, from unsafe.Pointer) {
  502     switch argSize {
  503     case 4:
  504         r.Floats[reg] = archFloat32ToReg(*(*float32)(from))
  505     case 8:
  506         r.Floats[reg] = *(*uint64)(from)
  507     default:
  508         panic("bad argSize")
  509     }
  510 }