...

Source file src/reflect/abi.go

Documentation: reflect

		 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/goexperiment"
		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 * goexperiment.RegabiArgsInt
		33  	floatArgRegs = abi.FloatArgRegs * goexperiment.RegabiArgsInt
		34  	floatRegSize = uintptr(abi.EffectiveFloatRegSize * goexperiment.RegabiArgsInt)
		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, 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, ptrSize, 1, 0b0)
	 180  		ptr = false
	 181  	}
	 182  	if !ok {
	 183  		a.stackAssign(ptrSize, 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, Ptr, 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 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, ptrSize, 2, 0b01)
	 219  	case Interface:
	 220  		return a.assignIntN(offset, ptrSize, 2, 0b10)
	 221  	case Slice:
	 222  		return a.assignIntN(offset, 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 != 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 += 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, 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, 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  

View as plain text