"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 }