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