Source file src/reflect/abi.go

     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 *abi.Type) *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 *abi.Type) (*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 rcvr.IfaceIndir() || 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 *abi.Type, offset uintptr) bool {
   199  	switch Kind(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 *abi.Type) 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.InSlice() {
   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.OutSlice() {
   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  }
   511  

View as plain text