github.com/twelsh-aw/go/src@v0.0.0-20230516233729-a56fe86a7c81/reflect/abi.go (about) 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 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 *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 }