// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package reflect

import (
	
	
	
	
)

// These variables are used by the register assignment
// algorithm in this file.
//
// They should be modified with care (no other reflect code
// may be executing) and are generally only modified
// when testing this package.
//
// They should never be set higher than their internal/abi
// constant counterparts, because the system relies on a
// structure that is at least large enough to hold the
// registers the system supports.
//
// Currently they're set to zero because using the actual
// constants will break every part of the toolchain that
// uses reflect to call functions (e.g. go test, or anything
// that uses text/template). The values that are currently
// commented out there should be the actual values once
// we're ready to use the register ABI everywhere.
var (
	intArgRegs   = abi.IntArgRegs * goexperiment.RegabiArgsInt
	floatArgRegs = abi.FloatArgRegs * goexperiment.RegabiArgsInt
	floatRegSize = uintptr(abi.EffectiveFloatRegSize * goexperiment.RegabiArgsInt)
)

// abiStep represents an ABI "instruction." Each instruction
// describes one part of how to translate between a Go value
// in memory and a call frame.
type abiStep struct {
	kind abiStepKind

	// offset and size together describe a part of a Go value
	// in memory.
	offset uintptr
	size   uintptr // size in bytes of the part

	// These fields describe the ABI side of the translation.
	stkOff uintptr // stack offset, used if kind == abiStepStack
	ireg   int     // integer register index, used if kind == abiStepIntReg or kind == abiStepPointer
	freg   int     // FP register index, used if kind == abiStepFloatReg
}

// abiStepKind is the "op-code" for an abiStep instruction.
type abiStepKind int

const (
	abiStepBad      abiStepKind = iota
	abiStepStack                // copy to/from stack
	abiStepIntReg               // copy to/from integer register
	abiStepPointer              // copy pointer to/from integer register
	abiStepFloatReg             // copy to/from FP register
)

// abiSeq represents a sequence of ABI instructions for copying
// from a series of reflect.Values to a call frame (for call arguments)
// or vice-versa (for call results).
//
// An abiSeq should be populated by calling its addArg method.
type abiSeq struct {
	// steps is the set of instructions.
	//
	// The instructions are grouped together by whole arguments,
	// with the starting index for the instructions
	// of the i'th Go value available in valueStart.
	//
	// For instance, if this abiSeq represents 3 arguments
	// passed to a function, then the 2nd argument's steps
	// begin at steps[valueStart[1]].
	//
	// Because reflect accepts Go arguments in distinct
	// Values and each Value is stored separately, each abiStep
	// that begins a new argument will have its offset
	// field == 0.
	steps      []abiStep
	valueStart []int

	stackBytes   uintptr // stack space used
	iregs, fregs int     // registers used
}

func ( *abiSeq) () {
	for ,  := range .steps {
		println("part", , .kind, .offset, .size, .stkOff, .ireg, .freg)
	}
	print("values ")
	for ,  := range .valueStart {
		print(, " ")
	}
	println()
	println("stack", .stackBytes)
	println("iregs", .iregs)
	println("fregs", .fregs)
}

// stepsForValue returns the ABI instructions for translating
// the i'th Go argument or return value represented by this
// abiSeq to the Go ABI.
func ( *abiSeq) ( int) []abiStep {
	 := .valueStart[]
	var  int
	if  == len(.valueStart)-1 {
		 = len(.steps)
	} else {
		 = .valueStart[+1]
	}
	return .steps[:]
}

// addArg extends the abiSeq with a new Go value of type t.
//
// If the value was stack-assigned, returns the single
// abiStep describing that translation, and nil otherwise.
func ( *abiSeq) ( *rtype) *abiStep {
	// We'll always be adding a new value, so do that first.
	 := len(.steps)
	.valueStart = append(.valueStart, )
	if .size == 0 {
		// If the size of the argument type is zero, then
		// in order to degrade gracefully into ABI0, we need
		// to stack-assign this type. The reason is that
		// although zero-sized types take up no space on the
		// stack, they do cause the next argument to be aligned.
		// So just do that here, but don't bother actually
		// generating a new ABI step for it (there's nothing to
		// actually copy).
		//
		// We cannot handle this in the recursive case of
		// regAssign because zero-sized *fields* of a
		// non-zero-sized struct do not cause it to be
		// stack-assigned. So we need a special case here
		// at the top.
		.stackBytes = align(.stackBytes, uintptr(.align))
		return nil
	}
	// Hold a copy of "a" so that we can roll back if
	// register assignment fails.
	 := *
	if !.regAssign(, 0) {
		// Register assignment failed. Roll back any changes
		// and stack-assign.
		* = 
		.stackAssign(.size, uintptr(.align))
		return &.steps[len(.steps)-1]
	}
	return nil
}

// addRcvr extends the abiSeq with a new method call
// receiver according to the interface calling convention.
//
// If the receiver was stack-assigned, returns the single
// abiStep describing that translation, and nil otherwise.
// Returns true if the receiver is a pointer.
func ( *abiSeq) ( *rtype) (*abiStep, bool) {
	// The receiver is always one word.
	.valueStart = append(.valueStart, len(.steps))
	var ,  bool
	if ifaceIndir() || .pointers() {
		 = .assignIntN(0, goarch.PtrSize, 1, 0b1)
		 = true
	} else {
		// TODO(mknyszek): Is this case even possible?
		// The interface data work never contains a non-pointer
		// value. This case was copied over from older code
		// in the reflect package which only conditionally added
		// a pointer bit to the reflect.(Value).Call stack frame's
		// GC bitmap.
		 = .assignIntN(0, goarch.PtrSize, 1, 0b0)
		 = false
	}
	if ! {
		.stackAssign(goarch.PtrSize, goarch.PtrSize)
		return &.steps[len(.steps)-1], 
	}
	return nil, 
}

// regAssign attempts to reserve argument registers for a value of
// type t, stored at some offset.
//
// It returns whether or not the assignment succeeded, but
// leaves any changes it made to a.steps behind, so the caller
// must undo that work by adjusting a.steps if it fails.
//
// This method along with the assign* methods represent the
// complete register-assignment algorithm for the Go ABI.
func ( *abiSeq) ( *rtype,  uintptr) bool {
	switch .Kind() {
	case UnsafePointer, Pointer, Chan, Map, Func:
		return .assignIntN(, .size, 1, 0b1)
	case Bool, Int, Uint, Int8, Uint8, Int16, Uint16, Int32, Uint32, Uintptr:
		return .assignIntN(, .size, 1, 0b0)
	case Int64, Uint64:
		switch goarch.PtrSize {
		case 4:
			return .assignIntN(, 4, 2, 0b0)
		case 8:
			return .assignIntN(, 8, 1, 0b0)
		}
	case Float32, Float64:
		return .assignFloatN(, .size, 1)
	case Complex64:
		return .assignFloatN(, 4, 2)
	case Complex128:
		return .assignFloatN(, 8, 2)
	case String:
		return .assignIntN(, goarch.PtrSize, 2, 0b01)
	case Interface:
		return .assignIntN(, goarch.PtrSize, 2, 0b10)
	case Slice:
		return .assignIntN(, goarch.PtrSize, 3, 0b001)
	case Array:
		 := (*arrayType)(unsafe.Pointer())
		switch .len {
		case 0:
			// There's nothing to assign, so don't modify
			// a.steps but succeed so the caller doesn't
			// try to stack-assign this value.
			return true
		case 1:
			return .(.elem, )
		default:
			return false
		}
	case Struct:
		 := (*structType)(unsafe.Pointer())
		for  := range .fields {
			 := &.fields[]
			if !.(.typ, +.offset()) {
				return false
			}
		}
		return true
	default:
		print("t.Kind == ", .Kind(), "\n")
		panic("unknown type kind")
	}
	panic("unhandled register assignment path")
}

// assignIntN assigns n values to registers, each "size" bytes large,
// from the data at [offset, offset+n*size) in memory. Each value at
// [offset+i*size, offset+(i+1)*size) for i < n is assigned to the
// next n integer registers.
//
// Bit i in ptrMap indicates whether the i'th value is a pointer.
// n must be <= 8.
//
// Returns whether assignment succeeded.
func ( *abiSeq) (,  uintptr,  int,  uint8) bool {
	if  > 8 ||  < 0 {
		panic("invalid n")
	}
	if  != 0 &&  != goarch.PtrSize {
		panic("non-empty pointer map passed for non-pointer-size values")
	}
	if .iregs+ > intArgRegs {
		return false
	}
	for  := 0;  < ; ++ {
		 := abiStepIntReg
		if &(uint8(1)<<) != 0 {
			 = abiStepPointer
		}
		.steps = append(.steps, abiStep{
			kind:   ,
			offset:  + uintptr()*,
			size:   ,
			ireg:   .iregs,
		})
		.iregs++
	}
	return true
}

// assignFloatN assigns n values to registers, each "size" bytes large,
// from the data at [offset, offset+n*size) in memory. Each value at
// [offset+i*size, offset+(i+1)*size) for i < n is assigned to the
// next n floating-point registers.
//
// Returns whether assignment succeeded.
func ( *abiSeq) (,  uintptr,  int) bool {
	if  < 0 {
		panic("invalid n")
	}
	if .fregs+ > floatArgRegs || floatRegSize <  {
		return false
	}
	for  := 0;  < ; ++ {
		.steps = append(.steps, abiStep{
			kind:   abiStepFloatReg,
			offset:  + uintptr()*,
			size:   ,
			freg:   .fregs,
		})
		.fregs++
	}
	return true
}

// stackAssign reserves space for one value that is "size" bytes
// large with alignment "alignment" to the stack.
//
// Should not be called directly; use addArg instead.
func ( *abiSeq) (,  uintptr) {
	.stackBytes = align(.stackBytes, )
	.steps = append(.steps, abiStep{
		kind:   abiStepStack,
		offset: 0, // Only used for whole arguments, so the memory offset is 0.
		size:   ,
		stkOff: .stackBytes,
	})
	.stackBytes += 
}

// abiDesc describes the ABI for a function or method.
type abiDesc struct {
	// call and ret represent the translation steps for
	// the call and return paths of a Go function.
	call, ret abiSeq

	// These fields describe the stack space allocated
	// for the call. stackCallArgsSize is the amount of space
	// reserved for arguments but not return values. retOffset
	// is the offset at which return values begin, and
	// spill is the size in bytes of additional space reserved
	// to spill argument registers into in case of preemption in
	// reflectcall's stack frame.
	stackCallArgsSize, retOffset, spill uintptr

	// stackPtrs is a bitmap that indicates whether
	// each word in the ABI stack space (stack-assigned
	// args + return values) is a pointer. Used
	// as the heap pointer bitmap for stack space
	// passed to reflectcall.
	stackPtrs *bitVector

	// inRegPtrs is a bitmap whose i'th bit indicates
	// whether the i'th integer argument register contains
	// a pointer. Used by makeFuncStub and methodValueCall
	// to make result pointers visible to the GC.
	//
	// outRegPtrs is the same, but for result values.
	// Used by reflectcall to make result pointers visible
	// to the GC.
	inRegPtrs, outRegPtrs abi.IntArgRegBitmap
}

func ( *abiDesc) () {
	println("ABI")
	println("call")
	.call.dump()
	println("ret")
	.ret.dump()
	println("stackCallArgsSize", .stackCallArgsSize)
	println("retOffset", .retOffset)
	println("spill", .spill)
	print("inRegPtrs:")
	dumpPtrBitMap(.inRegPtrs)
	println()
	print("outRegPtrs:")
	dumpPtrBitMap(.outRegPtrs)
	println()
}

func dumpPtrBitMap( abi.IntArgRegBitmap) {
	for  := 0;  < intArgRegs; ++ {
		 := 0
		if .Get() {
			 = 1
		}
		print(" ", )
	}
}

func newAbiDesc( *funcType,  *rtype) abiDesc {
	// We need to add space for this argument to
	// the frame so that it can spill args into it.
	//
	// The size of this space is just the sum of the sizes
	// of each register-allocated type.
	//
	// TODO(mknyszek): Remove this when we no longer have
	// caller reserved spill space.
	 := uintptr(0)

	// Compute gc program & stack bitmap for stack arguments
	 := new(bitVector)

	// Compute the stack frame pointer bitmap and register
	// pointer bitmap for arguments.
	 := abi.IntArgRegBitmap{}

	// Compute abiSeq for input parameters.
	var  abiSeq
	if  != nil {
		,  := .addRcvr()
		if  != nil {
			if  {
				.append(1)
			} else {
				.append(0)
			}
		} else {
			 += goarch.PtrSize
		}
	}
	for ,  := range .in() {
		 := .addArg()
		if  != nil {
			addTypeBits(, .stkOff, )
		} else {
			 = align(, uintptr(.align))
			 += .size
			for ,  := range .stepsForValue() {
				if .kind == abiStepPointer {
					.Set(.ireg)
				}
			}
		}
	}
	 = align(, goarch.PtrSize)

	// From the input parameters alone, we now know
	// the stackCallArgsSize and retOffset.
	 := .stackBytes
	 := align(.stackBytes, goarch.PtrSize)

	// Compute the stack frame pointer bitmap and register
	// pointer bitmap for return values.
	 := abi.IntArgRegBitmap{}

	// Compute abiSeq for output parameters.
	var  abiSeq
	// Stack-assigned return values do not share
	// space with arguments like they do with registers,
	// so we need to inject a stack offset here.
	// Fake it by artificially extending stackBytes by
	// the return offset.
	.stackBytes = 
	for ,  := range .out() {
		 := .addArg()
		if  != nil {
			addTypeBits(, .stkOff, )
		} else {
			for ,  := range .stepsForValue() {
				if .kind == abiStepPointer {
					.Set(.ireg)
				}
			}
		}
	}
	// Undo the faking from earlier so that stackBytes
	// is accurate.
	.stackBytes -= 
	return abiDesc{, , , , , , , }
}

// intFromReg loads an argSize sized integer from reg and places it at to.
//
// argSize must be non-zero, fit in a register, and a power-of-two.
func intFromReg( *abi.RegArgs,  int,  uintptr,  unsafe.Pointer) {
	memmove(, .IntRegArgAddr(, ), )
}

// intToReg loads an argSize sized integer and stores it into reg.
//
// argSize must be non-zero, fit in a register, and a power-of-two.
func intToReg( *abi.RegArgs,  int,  uintptr,  unsafe.Pointer) {
	memmove(.IntRegArgAddr(, ), , )
}

// floatFromReg loads a float value from its register representation in r.
//
// argSize must be 4 or 8.
func floatFromReg( *abi.RegArgs,  int,  uintptr,  unsafe.Pointer) {
	switch  {
	case 4:
		*(*float32)() = archFloat32FromReg(.Floats[])
	case 8:
		*(*float64)() = *(*float64)(unsafe.Pointer(&.Floats[]))
	default:
		panic("bad argSize")
	}
}

// floatToReg stores a float value in its register representation in r.
//
// argSize must be either 4 or 8.
func floatToReg( *abi.RegArgs,  int,  uintptr,  unsafe.Pointer) {
	switch  {
	case 4:
		.Floats[] = archFloat32ToReg(*(*float32)())
	case 8:
		.Floats[] = *(*uint64)()
	default:
		panic("bad argSize")
	}
}