blob: 5a4ac8cf7c10596cfebf7d278d07529350dfd7ec [file] [log] [blame]
// Copyright 2009 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 implements run-time reflection, allowing a program to
// manipulate objects with arbitrary types. The typical use is to take a value
// with static type interface{} and extract its dynamic type information by
// calling TypeOf, which returns a Type.
//
// A call to ValueOf returns a Value representing the run-time data.
// Zero takes a Type and returns a Value representing a zero value
// for that type.
//
// See "The Laws of Reflection" for an introduction to reflection in Go:
// http://golang.org/doc/articles/laws_of_reflection.html
package reflect
import (
"runtime"
"strconv"
"sync"
"unsafe"
)
// Type is the representation of a Go type.
//
// Not all methods apply to all kinds of types. Restrictions,
// if any, are noted in the documentation for each method.
// Use the Kind method to find out the kind of type before
// calling kind-specific methods. Calling a method
// inappropriate to the kind of type causes a run-time panic.
type Type interface {
// Methods applicable to all types.
// Align returns the alignment in bytes of a value of
// this type when allocated in memory.
Align() int
// FieldAlign returns the alignment in bytes of a value of
// this type when used as a field in a struct.
FieldAlign() int
// Method returns the i'th method in the type's method set.
// It panics if i is not in the range [0, NumMethod()).
//
// For a non-interface type T or *T, the returned Method's Type and Func
// fields describe a function whose first argument is the receiver.
//
// For an interface type, the returned Method's Type field gives the
// method signature, without a receiver, and the Func field is nil.
Method(int) Method
// MethodByName returns the method with that name in the type's
// method set and a boolean indicating if the method was found.
//
// For a non-interface type T or *T, the returned Method's Type and Func
// fields describe a function whose first argument is the receiver.
//
// For an interface type, the returned Method's Type field gives the
// method signature, without a receiver, and the Func field is nil.
MethodByName(string) (Method, bool)
// NumMethod returns the number of methods in the type's method set.
NumMethod() int
// Name returns the type's name within its package.
// It returns an empty string for unnamed types.
Name() string
// PkgPath returns a named type's package path, that is, the import path
// that uniquely identifies the package, such as "encoding/base64".
// If the type was predeclared (string, error) or unnamed (*T, struct{}, []int),
// the package path will be the empty string.
PkgPath() string
// Size returns the number of bytes needed to store
// a value of the given type; it is analogous to unsafe.Sizeof.
Size() uintptr
// String returns a string representation of the type.
// The string representation may use shortened package names
// (e.g., base64 instead of "encoding/base64") and is not
// guaranteed to be unique among types. To test for equality,
// compare the Types directly.
String() string
// Kind returns the specific kind of this type.
Kind() Kind
// Implements returns true if the type implements the interface type u.
Implements(u Type) bool
// AssignableTo returns true if a value of the type is assignable to type u.
AssignableTo(u Type) bool
// ConvertibleTo returns true if a value of the type is convertible to type u.
ConvertibleTo(u Type) bool
// Methods applicable only to some types, depending on Kind.
// The methods allowed for each kind are:
//
// Int*, Uint*, Float*, Complex*: Bits
// Array: Elem, Len
// Chan: ChanDir, Elem
// Func: In, NumIn, Out, NumOut, IsVariadic.
// Map: Key, Elem
// Ptr: Elem
// Slice: Elem
// Struct: Field, FieldByIndex, FieldByName, FieldByNameFunc, NumField
// Bits returns the size of the type in bits.
// It panics if the type's Kind is not one of the
// sized or unsized Int, Uint, Float, or Complex kinds.
Bits() int
// ChanDir returns a channel type's direction.
// It panics if the type's Kind is not Chan.
ChanDir() ChanDir
// IsVariadic returns true if a function type's final input parameter
// is a "..." parameter. If so, t.In(t.NumIn() - 1) returns the parameter's
// implicit actual type []T.
//
// For concreteness, if t represents func(x int, y ... float64), then
//
// t.NumIn() == 2
// t.In(0) is the reflect.Type for "int"
// t.In(1) is the reflect.Type for "[]float64"
// t.IsVariadic() == true
//
// IsVariadic panics if the type's Kind is not Func.
IsVariadic() bool
// Elem returns a type's element type.
// It panics if the type's Kind is not Array, Chan, Map, Ptr, or Slice.
Elem() Type
// Field returns a struct type's i'th field.
// It panics if the type's Kind is not Struct.
// It panics if i is not in the range [0, NumField()).
Field(i int) StructField
// FieldByIndex returns the nested field corresponding
// to the index sequence. It is equivalent to calling Field
// successively for each index i.
// It panics if the type's Kind is not Struct.
FieldByIndex(index []int) StructField
// FieldByName returns the struct field with the given name
// and a boolean indicating if the field was found.
FieldByName(name string) (StructField, bool)
// FieldByNameFunc returns the first struct field with a name
// that satisfies the match function and a boolean indicating if
// the field was found.
FieldByNameFunc(match func(string) bool) (StructField, bool)
// In returns the type of a function type's i'th input parameter.
// It panics if the type's Kind is not Func.
// It panics if i is not in the range [0, NumIn()).
In(i int) Type
// Key returns a map type's key type.
// It panics if the type's Kind is not Map.
Key() Type
// Len returns an array type's length.
// It panics if the type's Kind is not Array.
Len() int
// NumField returns a struct type's field count.
// It panics if the type's Kind is not Struct.
NumField() int
// NumIn returns a function type's input parameter count.
// It panics if the type's Kind is not Func.
NumIn() int
// NumOut returns a function type's output parameter count.
// It panics if the type's Kind is not Func.
NumOut() int
// Out returns the type of a function type's i'th output parameter.
// It panics if the type's Kind is not Func.
// It panics if i is not in the range [0, NumOut()).
Out(i int) Type
common() *rtype
uncommon() *uncommonType
}
// BUG(rsc): FieldByName and related functions consider struct field names to be equal
// if the names are equal, even if they are unexported names originating
// in different packages. The practical effect of this is that the result of
// t.FieldByName("x") is not well defined if the struct type t contains
// multiple fields named x (embedded from different packages).
// FieldByName may return one of the fields named x or may report that there are none.
// See golang.org/issue/4876 for more details.
/*
* These data structures are known to the compiler (../../cmd/gc/reflect.c).
* A few are known to ../runtime/type.go to convey to debuggers.
* They are also known to ../runtime/type.h.
*/
// A Kind represents the specific kind of type that a Type represents.
// The zero Kind is not a valid kind.
type Kind uint
const (
Invalid Kind = iota
Bool
Int
Int8
Int16
Int32
Int64
Uint
Uint8
Uint16
Uint32
Uint64
Uintptr
Float32
Float64
Complex64
Complex128
Array
Chan
Func
Interface
Map
Ptr
Slice
String
Struct
UnsafePointer
)
// rtype is the common implementation of most values.
// It is embedded in other, public struct types, but always
// with a unique tag like `reflect:"array"` or `reflect:"ptr"`
// so that code cannot convert from, say, *arrayType to *ptrType.
type rtype struct {
size uintptr // size in bytes
hash uint32 // hash of type; avoids computation in hash tables
_ uint8 // unused/padding
align uint8 // alignment of variable with this type
fieldAlign uint8 // alignment of struct field with this type
kind uint8 // enumeration for C
alg *uintptr // algorithm table (../runtime/runtime.h:/Alg)
gc unsafe.Pointer // garbage collection data
string *string // string form; unnecessary but undeniably useful
*uncommonType // (relatively) uncommon fields
ptrToThis *rtype // type for pointer to this type, if used in binary or has methods
zero unsafe.Pointer // pointer to zero value
}
// Method on non-interface type
type method struct {
name *string // name of method
pkgPath *string // nil for exported Names; otherwise import path
mtyp *rtype // method type (without receiver)
typ *rtype // .(*FuncType) underneath (with receiver)
ifn unsafe.Pointer // fn used in interface call (one-word receiver)
tfn unsafe.Pointer // fn used for normal method call
}
// uncommonType is present only for types with names or methods
// (if T is a named type, the uncommonTypes for T and *T have methods).
// Using a pointer to this struct reduces the overall size required
// to describe an unnamed type with no methods.
type uncommonType struct {
name *string // name of type
pkgPath *string // import path; nil for built-in types like int, string
methods []method // methods associated with type
}
// ChanDir represents a channel type's direction.
type ChanDir int
const (
RecvDir ChanDir = 1 << iota // <-chan
SendDir // chan<-
BothDir = RecvDir | SendDir // chan
)
// arrayType represents a fixed array type.
type arrayType struct {
rtype `reflect:"array"`
elem *rtype // array element type
slice *rtype // slice type
len uintptr
}
// chanType represents a channel type.
type chanType struct {
rtype `reflect:"chan"`
elem *rtype // channel element type
dir uintptr // channel direction (ChanDir)
}
// funcType represents a function type.
type funcType struct {
rtype `reflect:"func"`
dotdotdot bool // last input parameter is ...
in []*rtype // input parameter types
out []*rtype // output parameter types
}
// imethod represents a method on an interface type
type imethod struct {
name *string // name of method
pkgPath *string // nil for exported Names; otherwise import path
typ *rtype // .(*FuncType) underneath
}
// interfaceType represents an interface type.
type interfaceType struct {
rtype `reflect:"interface"`
methods []imethod // sorted by hash
}
// mapType represents a map type.
type mapType struct {
rtype `reflect:"map"`
key *rtype // map key type
elem *rtype // map element (value) type
bucket *rtype // internal bucket structure
hmap *rtype // internal map header
}
// ptrType represents a pointer type.
type ptrType struct {
rtype `reflect:"ptr"`
elem *rtype // pointer element (pointed at) type
}
// sliceType represents a slice type.
type sliceType struct {
rtype `reflect:"slice"`
elem *rtype // slice element type
}
// Struct field
type structField struct {
name *string // nil for embedded fields
pkgPath *string // nil for exported Names; otherwise import path
typ *rtype // type of field
tag *string // nil if no tag
offset uintptr // byte offset of field within struct
}
// structType represents a struct type.
type structType struct {
rtype `reflect:"struct"`
fields []structField // sorted by offset
}
// NOTE: These are copied from ../runtime/mgc0.h.
// They must be kept in sync.
const (
_GC_END = iota
_GC_PTR
_GC_APTR
_GC_ARRAY_START
_GC_ARRAY_NEXT
_GC_CALL
_GC_CHAN_PTR
_GC_STRING
_GC_EFACE
_GC_IFACE
_GC_SLICE
_GC_REGION
_GC_NUM_INSTR
)
/*
* The compiler knows the exact layout of all the data structures above.
* The compiler does not know about the data structures and methods below.
*/
// Method represents a single method.
type Method struct {
// Name is the method name.
// PkgPath is the package path that qualifies a lower case (unexported)
// method name. It is empty for upper case (exported) method names.
// The combination of PkgPath and Name uniquely identifies a method
// in a method set.
// See http://golang.org/ref/spec#Uniqueness_of_identifiers
Name string
PkgPath string
Type Type // method type
Func Value // func with receiver as first argument
Index int // index for Type.Method
}
// High bit says whether type has
// embedded pointers,to help garbage collector.
const (
kindMask = 0x7f
kindNoPointers = 0x80
)
func (k Kind) String() string {
if int(k) < len(kindNames) {
return kindNames[k]
}
return "kind" + strconv.Itoa(int(k))
}
var kindNames = []string{
Invalid: "invalid",
Bool: "bool",
Int: "int",
Int8: "int8",
Int16: "int16",
Int32: "int32",
Int64: "int64",
Uint: "uint",
Uint8: "uint8",
Uint16: "uint16",
Uint32: "uint32",
Uint64: "uint64",
Uintptr: "uintptr",
Float32: "float32",
Float64: "float64",
Complex64: "complex64",
Complex128: "complex128",
Array: "array",
Chan: "chan",
Func: "func",
Interface: "interface",
Map: "map",
Ptr: "ptr",
Slice: "slice",
String: "string",
Struct: "struct",
UnsafePointer: "unsafe.Pointer",
}
func (t *uncommonType) uncommon() *uncommonType {
return t
}
func (t *uncommonType) PkgPath() string {
if t == nil || t.pkgPath == nil {
return ""
}
return *t.pkgPath
}
func (t *uncommonType) Name() string {
if t == nil || t.name == nil {
return ""
}
return *t.name
}
func (t *rtype) String() string { return *t.string }
func (t *rtype) Size() uintptr { return t.size }
func (t *rtype) Bits() int {
if t == nil {
panic("reflect: Bits of nil Type")
}
k := t.Kind()
if k < Int || k > Complex128 {
panic("reflect: Bits of non-arithmetic Type " + t.String())
}
return int(t.size) * 8
}
func (t *rtype) Align() int { return int(t.align) }
func (t *rtype) FieldAlign() int { return int(t.fieldAlign) }
func (t *rtype) Kind() Kind { return Kind(t.kind & kindMask) }
func (t *rtype) pointers() bool { return t.kind&kindNoPointers == 0 }
func (t *rtype) common() *rtype { return t }
func (t *uncommonType) Method(i int) (m Method) {
if t == nil || i < 0 || i >= len(t.methods) {
panic("reflect: Method index out of range")
}
p := &t.methods[i]
if p.name != nil {
m.Name = *p.name
}
fl := flag(Func) << flagKindShift
if p.pkgPath != nil {
m.PkgPath = *p.pkgPath
fl |= flagRO
}
mt := p.typ
m.Type = mt
fn := unsafe.Pointer(&p.tfn)
m.Func = Value{mt, fn, 0, fl}
m.Index = i
return
}
func (t *uncommonType) NumMethod() int {
if t == nil {
return 0
}
return len(t.methods)
}
func (t *uncommonType) MethodByName(name string) (m Method, ok bool) {
if t == nil {
return
}
var p *method
for i := range t.methods {
p = &t.methods[i]
if p.name != nil && *p.name == name {
return t.Method(i), true
}
}
return
}
// TODO(rsc): 6g supplies these, but they are not
// as efficient as they could be: they have commonType
// as the receiver instead of *rtype.
func (t *rtype) NumMethod() int {
if t.Kind() == Interface {
tt := (*interfaceType)(unsafe.Pointer(t))
return tt.NumMethod()
}
return t.uncommonType.NumMethod()
}
func (t *rtype) Method(i int) (m Method) {
if t.Kind() == Interface {
tt := (*interfaceType)(unsafe.Pointer(t))
return tt.Method(i)
}
return t.uncommonType.Method(i)
}
func (t *rtype) MethodByName(name string) (m Method, ok bool) {
if t.Kind() == Interface {
tt := (*interfaceType)(unsafe.Pointer(t))
return tt.MethodByName(name)
}
return t.uncommonType.MethodByName(name)
}
func (t *rtype) PkgPath() string {
return t.uncommonType.PkgPath()
}
func (t *rtype) Name() string {
return t.uncommonType.Name()
}
func (t *rtype) ChanDir() ChanDir {
if t.Kind() != Chan {
panic("reflect: ChanDir of non-chan type")
}
tt := (*chanType)(unsafe.Pointer(t))
return ChanDir(tt.dir)
}
func (t *rtype) IsVariadic() bool {
if t.Kind() != Func {
panic("reflect: IsVariadic of non-func type")
}
tt := (*funcType)(unsafe.Pointer(t))
return tt.dotdotdot
}
func (t *rtype) Elem() Type {
switch t.Kind() {
case Array:
tt := (*arrayType)(unsafe.Pointer(t))
return toType(tt.elem)
case Chan:
tt := (*chanType)(unsafe.Pointer(t))
return toType(tt.elem)
case Map:
tt := (*mapType)(unsafe.Pointer(t))
return toType(tt.elem)
case Ptr:
tt := (*ptrType)(unsafe.Pointer(t))
return toType(tt.elem)
case Slice:
tt := (*sliceType)(unsafe.Pointer(t))
return toType(tt.elem)
}
panic("reflect: Elem of invalid type")
}
func (t *rtype) Field(i int) StructField {
if t.Kind() != Struct {
panic("reflect: Field of non-struct type")
}
tt := (*structType)(unsafe.Pointer(t))
return tt.Field(i)
}
func (t *rtype) FieldByIndex(index []int) StructField {
if t.Kind() != Struct {
panic("reflect: FieldByIndex of non-struct type")
}
tt := (*structType)(unsafe.Pointer(t))
return tt.FieldByIndex(index)
}
func (t *rtype) FieldByName(name string) (StructField, bool) {
if t.Kind() != Struct {
panic("reflect: FieldByName of non-struct type")
}
tt := (*structType)(unsafe.Pointer(t))
return tt.FieldByName(name)
}
func (t *rtype) FieldByNameFunc(match func(string) bool) (StructField, bool) {
if t.Kind() != Struct {
panic("reflect: FieldByNameFunc of non-struct type")
}
tt := (*structType)(unsafe.Pointer(t))
return tt.FieldByNameFunc(match)
}
func (t *rtype) In(i int) Type {
if t.Kind() != Func {
panic("reflect: In of non-func type")
}
tt := (*funcType)(unsafe.Pointer(t))
return toType(tt.in[i])
}
func (t *rtype) Key() Type {
if t.Kind() != Map {
panic("reflect: Key of non-map type")
}
tt := (*mapType)(unsafe.Pointer(t))
return toType(tt.key)
}
func (t *rtype) Len() int {
if t.Kind() != Array {
panic("reflect: Len of non-array type")
}
tt := (*arrayType)(unsafe.Pointer(t))
return int(tt.len)
}
func (t *rtype) NumField() int {
if t.Kind() != Struct {
panic("reflect: NumField of non-struct type")
}
tt := (*structType)(unsafe.Pointer(t))
return len(tt.fields)
}
func (t *rtype) NumIn() int {
if t.Kind() != Func {
panic("reflect: NumIn of non-func type")
}
tt := (*funcType)(unsafe.Pointer(t))
return len(tt.in)
}
func (t *rtype) NumOut() int {
if t.Kind() != Func {
panic("reflect: NumOut of non-func type")
}
tt := (*funcType)(unsafe.Pointer(t))
return len(tt.out)
}
func (t *rtype) Out(i int) Type {
if t.Kind() != Func {
panic("reflect: Out of non-func type")
}
tt := (*funcType)(unsafe.Pointer(t))
return toType(tt.out[i])
}
func (d ChanDir) String() string {
switch d {
case SendDir:
return "chan<-"
case RecvDir:
return "<-chan"
case BothDir:
return "chan"
}
return "ChanDir" + strconv.Itoa(int(d))
}
// Method returns the i'th method in the type's method set.
func (t *interfaceType) Method(i int) (m Method) {
if i < 0 || i >= len(t.methods) {
return
}
p := &t.methods[i]
m.Name = *p.name
if p.pkgPath != nil {
m.PkgPath = *p.pkgPath
}
m.Type = toType(p.typ)
m.Index = i
return
}
// NumMethod returns the number of interface methods in the type's method set.
func (t *interfaceType) NumMethod() int { return len(t.methods) }
// MethodByName method with the given name in the type's method set.
func (t *interfaceType) MethodByName(name string) (m Method, ok bool) {
if t == nil {
return
}
var p *imethod
for i := range t.methods {
p = &t.methods[i]
if *p.name == name {
return t.Method(i), true
}
}
return
}
// A StructField describes a single field in a struct.
type StructField struct {
// Name is the field name.
// PkgPath is the package path that qualifies a lower case (unexported)
// field name. It is empty for upper case (exported) field names.
// See http://golang.org/ref/spec#Uniqueness_of_identifiers
Name string
PkgPath string
Type Type // field type
Tag StructTag // field tag string
Offset uintptr // offset within struct, in bytes
Index []int // index sequence for Type.FieldByIndex
Anonymous bool // is an embedded field
}
// A StructTag is the tag string in a struct field.
//
// By convention, tag strings are a concatenation of
// optionally space-separated key:"value" pairs.
// Each key is a non-empty string consisting of non-control
// characters other than space (U+0020 ' '), quote (U+0022 '"'),
// and colon (U+003A ':'). Each value is quoted using U+0022 '"'
// characters and Go string literal syntax.
type StructTag string
// Get returns the value associated with key in the tag string.
// If there is no such key in the tag, Get returns the empty string.
// If the tag does not have the conventional format, the value
// returned by Get is unspecified.
func (tag StructTag) Get(key string) string {
for tag != "" {
// skip leading space
i := 0
for i < len(tag) && tag[i] == ' ' {
i++
}
tag = tag[i:]
if tag == "" {
break
}
// scan to colon.
// a space or a quote is a syntax error
i = 0
for i < len(tag) && tag[i] != ' ' && tag[i] != ':' && tag[i] != '"' {
i++
}
if i+1 >= len(tag) || tag[i] != ':' || tag[i+1] != '"' {
break
}
name := string(tag[:i])
tag = tag[i+1:]
// scan quoted string to find value
i = 1
for i < len(tag) && tag[i] != '"' {
if tag[i] == '\\' {
i++
}
i++
}
if i >= len(tag) {
break
}
qvalue := string(tag[:i+1])
tag = tag[i+1:]
if key == name {
value, _ := strconv.Unquote(qvalue)
return value
}
}
return ""
}
// Field returns the i'th struct field.
func (t *structType) Field(i int) (f StructField) {
if i < 0 || i >= len(t.fields) {
return
}
p := &t.fields[i]
f.Type = toType(p.typ)
if p.name != nil {
f.Name = *p.name
} else {
t := f.Type
if t.Kind() == Ptr {
t = t.Elem()
}
f.Name = t.Name()
f.Anonymous = true
}
if p.pkgPath != nil {
f.PkgPath = *p.pkgPath
}
if p.tag != nil {
f.Tag = StructTag(*p.tag)
}
f.Offset = p.offset
// NOTE(rsc): This is the only allocation in the interface
// presented by a reflect.Type. It would be nice to avoid,
// at least in the common cases, but we need to make sure
// that misbehaving clients of reflect cannot affect other
// uses of reflect. One possibility is CL 5371098, but we
// postponed that ugliness until there is a demonstrated
// need for the performance. This is issue 2320.
f.Index = []int{i}
return
}
// TODO(gri): Should there be an error/bool indicator if the index
// is wrong for FieldByIndex?
// FieldByIndex returns the nested field corresponding to index.
func (t *structType) FieldByIndex(index []int) (f StructField) {
f.Type = toType(&t.rtype)
for i, x := range index {
if i > 0 {
ft := f.Type
if ft.Kind() == Ptr && ft.Elem().Kind() == Struct {
ft = ft.Elem()
}
f.Type = ft
}
f = f.Type.Field(x)
}
return
}
// A fieldScan represents an item on the fieldByNameFunc scan work list.
type fieldScan struct {
typ *structType
index []int
}
// FieldByNameFunc returns the struct field with a name that satisfies the
// match function and a boolean to indicate if the field was found.
func (t *structType) FieldByNameFunc(match func(string) bool) (result StructField, ok bool) {
// This uses the same condition that the Go language does: there must be a unique instance
// of the match at a given depth level. If there are multiple instances of a match at the
// same depth, they annihilate each other and inhibit any possible match at a lower level.
// The algorithm is breadth first search, one depth level at a time.
// The current and next slices are work queues:
// current lists the fields to visit on this depth level,
// and next lists the fields on the next lower level.
current := []fieldScan{}
next := []fieldScan{{typ: t}}
// nextCount records the number of times an embedded type has been
// encountered and considered for queueing in the 'next' slice.
// We only queue the first one, but we increment the count on each.
// If a struct type T can be reached more than once at a given depth level,
// then it annihilates itself and need not be considered at all when we
// process that next depth level.
var nextCount map[*structType]int
// visited records the structs that have been considered already.
// Embedded pointer fields can create cycles in the graph of
// reachable embedded types; visited avoids following those cycles.
// It also avoids duplicated effort: if we didn't find the field in an
// embedded type T at level 2, we won't find it in one at level 4 either.
visited := map[*structType]bool{}
for len(next) > 0 {
current, next = next, current[:0]
count := nextCount
nextCount = nil
// Process all the fields at this depth, now listed in 'current'.
// The loop queues embedded fields found in 'next', for processing during the next
// iteration. The multiplicity of the 'current' field counts is recorded
// in 'count'; the multiplicity of the 'next' field counts is recorded in 'nextCount'.
for _, scan := range current {
t := scan.typ
if visited[t] {
// We've looked through this type before, at a higher level.
// That higher level would shadow the lower level we're now at,
// so this one can't be useful to us. Ignore it.
continue
}
visited[t] = true
for i := range t.fields {
f := &t.fields[i]
// Find name and type for field f.
var fname string
var ntyp *rtype
if f.name != nil {
fname = *f.name
} else {
// Anonymous field of type T or *T.
// Name taken from type.
ntyp = f.typ
if ntyp.Kind() == Ptr {
ntyp = ntyp.Elem().common()
}
fname = ntyp.Name()
}
// Does it match?
if match(fname) {
// Potential match
if count[t] > 1 || ok {
// Name appeared multiple times at this level: annihilate.
return StructField{}, false
}
result = t.Field(i)
result.Index = nil
result.Index = append(result.Index, scan.index...)
result.Index = append(result.Index, i)
ok = true
continue
}
// Queue embedded struct fields for processing with next level,
// but only if we haven't seen a match yet at this level and only
// if the embedded types haven't already been queued.
if ok || ntyp == nil || ntyp.Kind() != Struct {
continue
}
styp := (*structType)(unsafe.Pointer(ntyp))
if nextCount[styp] > 0 {
nextCount[styp] = 2 // exact multiple doesn't matter
continue
}
if nextCount == nil {
nextCount = map[*structType]int{}
}
nextCount[styp] = 1
if count[t] > 1 {
nextCount[styp] = 2 // exact multiple doesn't matter
}
var index []int
index = append(index, scan.index...)
index = append(index, i)
next = append(next, fieldScan{styp, index})
}
}
if ok {
break
}
}
return
}
// FieldByName returns the struct field with the given name
// and a boolean to indicate if the field was found.
func (t *structType) FieldByName(name string) (f StructField, present bool) {
// Quick check for top-level name, or struct without anonymous fields.
hasAnon := false
if name != "" {
for i := range t.fields {
tf := &t.fields[i]
if tf.name == nil {
hasAnon = true
continue
}
if *tf.name == name {
return t.Field(i), true
}
}
}
if !hasAnon {
return
}
return t.FieldByNameFunc(func(s string) bool { return s == name })
}
// TypeOf returns the reflection Type of the value in the interface{}.
// TypeOf(nil) returns nil.
func TypeOf(i interface{}) Type {
eface := *(*emptyInterface)(unsafe.Pointer(&i))
return toType(eface.typ)
}
// ptrMap is the cache for PtrTo.
var ptrMap struct {
sync.RWMutex
m map[*rtype]*ptrType
}
// garbage collection bytecode program for pointer to memory without pointers.
// See ../../cmd/gc/reflect.c:/^dgcsym1 and :/^dgcsym.
type ptrDataGC struct {
width uintptr // sizeof(ptr)
op uintptr // _GC_APTR
off uintptr // 0
end uintptr // _GC_END
}
var ptrDataGCProg = ptrDataGC{
width: unsafe.Sizeof((*byte)(nil)),
op: _GC_APTR,
off: 0,
end: _GC_END,
}
// garbage collection bytecode program for pointer to memory with pointers.
// See ../../cmd/gc/reflect.c:/^dgcsym1 and :/^dgcsym.
type ptrGC struct {
width uintptr // sizeof(ptr)
op uintptr // _GC_PTR
off uintptr // 0
elemgc unsafe.Pointer // element gc type
end uintptr // _GC_END
}
// PtrTo returns the pointer type with element t.
// For example, if t represents type Foo, PtrTo(t) represents *Foo.
func PtrTo(t Type) Type {
return t.(*rtype).ptrTo()
}
func (t *rtype) ptrTo() *rtype {
if p := t.ptrToThis; p != nil {
return p
}
// Otherwise, synthesize one.
// This only happens for pointers with no methods.
// We keep the mapping in a map on the side, because
// this operation is rare and a separate map lets us keep
// the type structures in read-only memory.
ptrMap.RLock()
if m := ptrMap.m; m != nil {
if p := m[t]; p != nil {
ptrMap.RUnlock()
return &p.rtype
}
}
ptrMap.RUnlock()
ptrMap.Lock()
if ptrMap.m == nil {
ptrMap.m = make(map[*rtype]*ptrType)
}
p := ptrMap.m[t]
if p != nil {
// some other goroutine won the race and created it
ptrMap.Unlock()
return &p.rtype
}
// Create a new ptrType starting with the description
// of an *unsafe.Pointer.
p = new(ptrType)
var iptr interface{} = (*unsafe.Pointer)(nil)
prototype := *(**ptrType)(unsafe.Pointer(&iptr))
*p = *prototype
s := "*" + *t.string
p.string = &s
// For the type structures linked into the binary, the
// compiler provides a good hash of the string.
// Create a good hash for the new string by using
// the FNV-1 hash's mixing function to combine the
// old hash and the new "*".
p.hash = fnv1(t.hash, '*')
p.uncommonType = nil
p.ptrToThis = nil
p.zero = unsafe.Pointer(&make([]byte, p.size)[0])
p.elem = t
if t.kind&kindNoPointers != 0 {
p.gc = unsafe.Pointer(&ptrDataGCProg)
} else {
p.gc = unsafe.Pointer(&ptrGC{
width: p.size,
op: _GC_PTR,
off: 0,
elemgc: t.gc,
end: _GC_END,
})
}
// INCORRECT. Uncomment to check that TestPtrToGC fails when p.gc is wrong.
//p.gc = unsafe.Pointer(&badGC{width: p.size, end: _GC_END})
ptrMap.m[t] = p
ptrMap.Unlock()
return &p.rtype
}
// fnv1 incorporates the list of bytes into the hash x using the FNV-1 hash function.
func fnv1(x uint32, list ...byte) uint32 {
for _, b := range list {
x = x*16777619 ^ uint32(b)
}
return x
}
func (t *rtype) Implements(u Type) bool {
if u == nil {
panic("reflect: nil type passed to Type.Implements")
}
if u.Kind() != Interface {
panic("reflect: non-interface type passed to Type.Implements")
}
return implements(u.(*rtype), t)
}
func (t *rtype) AssignableTo(u Type) bool {
if u == nil {
panic("reflect: nil type passed to Type.AssignableTo")
}
uu := u.(*rtype)
return directlyAssignable(uu, t) || implements(uu, t)
}
func (t *rtype) ConvertibleTo(u Type) bool {
if u == nil {
panic("reflect: nil type passed to Type.ConvertibleTo")
}
uu := u.(*rtype)
return convertOp(uu, t) != nil
}
// implements returns true if the type V implements the interface type T.
func implements(T, V *rtype) bool {
if T.Kind() != Interface {
return false
}
t := (*interfaceType)(unsafe.Pointer(T))
if len(t.methods) == 0 {
return true
}
// The same algorithm applies in both cases, but the
// method tables for an interface type and a concrete type
// are different, so the code is duplicated.
// In both cases the algorithm is a linear scan over the two
// lists - T's methods and V's methods - simultaneously.
// Since method tables are stored in a unique sorted order
// (alphabetical, with no duplicate method names), the scan
// through V's methods must hit a match for each of T's
// methods along the way, or else V does not implement T.
// This lets us run the scan in overall linear time instead of
// the quadratic time a naive search would require.
// See also ../runtime/iface.c.
if V.Kind() == Interface {
v := (*interfaceType)(unsafe.Pointer(V))
i := 0
for j := 0; j < len(v.methods); j++ {
tm := &t.methods[i]
vm := &v.methods[j]
if vm.name == tm.name && vm.pkgPath == tm.pkgPath && vm.typ == tm.typ {
if i++; i >= len(t.methods) {
return true
}
}
}
return false
}
v := V.uncommon()
if v == nil {
return false
}
i := 0
for j := 0; j < len(v.methods); j++ {
tm := &t.methods[i]
vm := &v.methods[j]
if vm.name == tm.name && vm.pkgPath == tm.pkgPath && vm.mtyp == tm.typ {
if i++; i >= len(t.methods) {
return true
}
}
}
return false
}
// directlyAssignable returns true if a value x of type V can be directly
// assigned (using memmove) to a value of type T.
// http://golang.org/doc/go_spec.html#Assignability
// Ignoring the interface rules (implemented elsewhere)
// and the ideal constant rules (no ideal constants at run time).
func directlyAssignable(T, V *rtype) bool {
// x's type V is identical to T?
if T == V {
return true
}
// Otherwise at least one of T and V must be unnamed
// and they must have the same kind.
if T.Name() != "" && V.Name() != "" || T.Kind() != V.Kind() {
return false
}
// x's type T and V must have identical underlying types.
return haveIdenticalUnderlyingType(T, V)
}
func haveIdenticalUnderlyingType(T, V *rtype) bool {
if T == V {
return true
}
kind := T.Kind()
if kind != V.Kind() {
return false
}
// Non-composite types of equal kind have same underlying type
// (the predefined instance of the type).
if Bool <= kind && kind <= Complex128 || kind == String || kind == UnsafePointer {
return true
}
// Composite types.
switch kind {
case Array:
return T.Elem() == V.Elem() && T.Len() == V.Len()
case Chan:
// Special case:
// x is a bidirectional channel value, T is a channel type,
// and x's type V and T have identical element types.
if V.ChanDir() == BothDir && T.Elem() == V.Elem() {
return true
}
// Otherwise continue test for identical underlying type.
return V.ChanDir() == T.ChanDir() && T.Elem() == V.Elem()
case Func:
t := (*funcType)(unsafe.Pointer(T))
v := (*funcType)(unsafe.Pointer(V))
if t.dotdotdot != v.dotdotdot || len(t.in) != len(v.in) || len(t.out) != len(v.out) {
return false
}
for i, typ := range t.in {
if typ != v.in[i] {
return false
}
}
for i, typ := range t.out {
if typ != v.out[i] {
return false
}
}
return true
case Interface:
t := (*interfaceType)(unsafe.Pointer(T))
v := (*interfaceType)(unsafe.Pointer(V))
if len(t.methods) == 0 && len(v.methods) == 0 {
return true
}
// Might have the same methods but still
// need a run time conversion.
return false
case Map:
return T.Key() == V.Key() && T.Elem() == V.Elem()
case Ptr, Slice:
return T.Elem() == V.Elem()
case Struct:
t := (*structType)(unsafe.Pointer(T))
v := (*structType)(unsafe.Pointer(V))
if len(t.fields) != len(v.fields) {
return false
}
for i := range t.fields {
tf := &t.fields[i]
vf := &v.fields[i]
if tf.name != vf.name && (tf.name == nil || vf.name == nil || *tf.name != *vf.name) {
return false
}
if tf.pkgPath != vf.pkgPath && (tf.pkgPath == nil || vf.pkgPath == nil || *tf.pkgPath != *vf.pkgPath) {
return false
}
if tf.typ != vf.typ {
return false
}
if tf.tag != vf.tag && (tf.tag == nil || vf.tag == nil || *tf.tag != *vf.tag) {
return false
}
if tf.offset != vf.offset {
return false
}
}
return true
}
return false
}
// typelinks is implemented in package runtime.
// It returns a slice of all the 'typelink' information in the binary,
// which is to say a slice of known types, sorted by string.
// Note that strings are not unique identifiers for types:
// there can be more than one with a given string.
// Only types we might want to look up are included:
// channels, maps, slices, and arrays.
func typelinks() []*rtype
// typesByString returns the subslice of typelinks() whose elements have
// the given string representation.
// It may be empty (no known types with that string) or may have
// multiple elements (multiple types with that string).
func typesByString(s string) []*rtype {
typ := typelinks()
// We are looking for the first index i where the string becomes >= s.
// This is a copy of sort.Search, with f(h) replaced by (*typ[h].string >= s).
i, j := 0, len(typ)
for i < j {
h := i + (j-i)/2 // avoid overflow when computing h
// i ≤ h < j
if !(*typ[h].string >= s) {
i = h + 1 // preserves f(i-1) == false
} else {
j = h // preserves f(j) == true
}
}
// i == j, f(i-1) == false, and f(j) (= f(i)) == true => answer is i.
// Having found the first, linear scan forward to find the last.
// We could do a second binary search, but the caller is going
// to do a linear scan anyway.
j = i
for j < len(typ) && *typ[j].string == s {
j++
}
// This slice will be empty if the string is not found.
return typ[i:j]
}
// The lookupCache caches ChanOf, MapOf, and SliceOf lookups.
var lookupCache struct {
sync.RWMutex
m map[cacheKey]*rtype
}
// A cacheKey is the key for use in the lookupCache.
// Four values describe any of the types we are looking for:
// type kind, one or two subtypes, and an extra integer.
type cacheKey struct {
kind Kind
t1 *rtype
t2 *rtype
extra uintptr
}
// cacheGet looks for a type under the key k in the lookupCache.
// If it finds one, it returns that type.
// If not, it returns nil with the cache locked.
// The caller is expected to use cachePut to unlock the cache.
func cacheGet(k cacheKey) Type {
lookupCache.RLock()
t := lookupCache.m[k]
lookupCache.RUnlock()
if t != nil {
return t
}
lookupCache.Lock()
t = lookupCache.m[k]
if t != nil {
lookupCache.Unlock()
return t
}
if lookupCache.m == nil {
lookupCache.m = make(map[cacheKey]*rtype)
}
return nil
}
// cachePut stores the given type in the cache, unlocks the cache,
// and returns the type. It is expected that the cache is locked
// because cacheGet returned nil.
func cachePut(k cacheKey, t *rtype) Type {
lookupCache.m[k] = t
lookupCache.Unlock()
return t
}
// garbage collection bytecode program for chan.
// See ../../cmd/gc/reflect.c:/^dgcsym1 and :/^dgcsym.
type chanGC struct {
width uintptr // sizeof(map)
op uintptr // _GC_CHAN_PTR
off uintptr // 0
typ *rtype // map type
end uintptr // _GC_END
}
type badGC struct {
width uintptr
end uintptr
}
// ChanOf returns the channel type with the given direction and element type.
// For example, if t represents int, ChanOf(RecvDir, t) represents <-chan int.
//
// The gc runtime imposes a limit of 64 kB on channel element types.
// If t's size is equal to or exceeds this limit, ChanOf panics.
func ChanOf(dir ChanDir, t Type) Type {
typ := t.(*rtype)
// Look in cache.
ckey := cacheKey{Chan, typ, nil, uintptr(dir)}
if ch := cacheGet(ckey); ch != nil {
return ch
}
// This restriction is imposed by the gc compiler and the runtime.
if typ.size >= 1<<16 {
lookupCache.Unlock()
panic("reflect.ChanOf: element size too large")
}
// Look in known types.
// TODO: Precedence when constructing string.
var s string
switch dir {
default:
lookupCache.Unlock()
panic("reflect.ChanOf: invalid dir")
case SendDir:
s = "chan<- " + *typ.string
case RecvDir:
s = "<-chan " + *typ.string
case BothDir:
s = "chan " + *typ.string
}
for _, tt := range typesByString(s) {
ch := (*chanType)(unsafe.Pointer(tt))
if ch.elem == typ && ch.dir == uintptr(dir) {
return cachePut(ckey, tt)
}
}
// Make a channel type.
var ichan interface{} = (chan unsafe.Pointer)(nil)
prototype := *(**chanType)(unsafe.Pointer(&ichan))
ch := new(chanType)
*ch = *prototype
ch.string = &s
ch.hash = fnv1(typ.hash, 'c', byte(dir))
ch.elem = typ
ch.uncommonType = nil
ch.ptrToThis = nil
ch.zero = unsafe.Pointer(&make([]byte, ch.size)[0])
ch.gc = unsafe.Pointer(&chanGC{
width: ch.size,
op: _GC_CHAN_PTR,
off: 0,
typ: &ch.rtype,
end: _GC_END,
})
// INCORRECT. Uncomment to check that TestChanOfGC fails when ch.gc is wrong.
//ch.gc = unsafe.Pointer(&badGC{width: ch.size, end: _GC_END})
return cachePut(ckey, &ch.rtype)
}
func ismapkey(*rtype) bool // implemented in runtime
// MapOf returns the map type with the given key and element types.
// For example, if k represents int and e represents string,
// MapOf(k, e) represents map[int]string.
//
// If the key type is not a valid map key type (that is, if it does
// not implement Go's == operator), MapOf panics.
func MapOf(key, elem Type) Type {
ktyp := key.(*rtype)
etyp := elem.(*rtype)
if !ismapkey(ktyp) {
panic("reflect.MapOf: invalid key type " + ktyp.String())
}
// Look in cache.
ckey := cacheKey{Map, ktyp, etyp, 0}
if mt := cacheGet(ckey); mt != nil {
return mt
}
// Look in known types.
s := "map[" + *ktyp.string + "]" + *etyp.string
for _, tt := range typesByString(s) {
mt := (*mapType)(unsafe.Pointer(tt))
if mt.key == ktyp && mt.elem == etyp {
return cachePut(ckey, tt)
}
}
// Make a map type.
var imap interface{} = (map[unsafe.Pointer]unsafe.Pointer)(nil)
prototype := *(**mapType)(unsafe.Pointer(&imap))
mt := new(mapType)
*mt = *prototype
mt.string = &s
mt.hash = fnv1(etyp.hash, 'm', byte(ktyp.hash>>24), byte(ktyp.hash>>16), byte(ktyp.hash>>8), byte(ktyp.hash))
mt.key = ktyp
mt.elem = etyp
mt.bucket = bucketOf(ktyp, etyp)
mt.hmap = hMapOf(mt.bucket)
mt.uncommonType = nil
mt.ptrToThis = nil
mt.zero = unsafe.Pointer(&make([]byte, mt.size)[0])
// INCORRECT. Uncomment to check that TestMapOfGC and TestMapOfGCValues
// fail when mt.gc is wrong.
//mt.gc = unsafe.Pointer(&badGC{width: mt.size, end: _GC_END})
return cachePut(ckey, &mt.rtype)
}
// Make sure these routines stay in sync with ../../pkg/runtime/hashmap.c!
// These types exist only for GC, so we only fill out GC relevant info.
// Currently, that's just size and the GC program. We also fill in string
// for possible debugging use.
const (
_BUCKETSIZE = 8
_MAXKEYSIZE = 128
_MAXVALSIZE = 128
)
func bucketOf(ktyp, etyp *rtype) *rtype {
if ktyp.size > _MAXKEYSIZE {
ktyp = PtrTo(ktyp).(*rtype)
}
if etyp.size > _MAXVALSIZE {
etyp = PtrTo(etyp).(*rtype)
}
ptrsize := unsafe.Sizeof(uintptr(0))
gc := make([]uintptr, 1) // first entry is size, filled in at the end
offset := _BUCKETSIZE * unsafe.Sizeof(uint8(0)) // topbits
gc = append(gc, _GC_PTR, offset, 0 /*self pointer set below*/) // overflow
offset += ptrsize
if runtime.GOARCH == "amd64p32" {
offset += 4
}
// keys
if ktyp.kind&kindNoPointers == 0 {
gc = append(gc, _GC_ARRAY_START, offset, _BUCKETSIZE, ktyp.size)
gc = appendGCProgram(gc, ktyp)
gc = append(gc, _GC_ARRAY_NEXT)
}
offset += _BUCKETSIZE * ktyp.size
// values
if etyp.kind&kindNoPointers == 0 {
gc = append(gc, _GC_ARRAY_START, offset, _BUCKETSIZE, etyp.size)
gc = appendGCProgram(gc, etyp)
gc = append(gc, _GC_ARRAY_NEXT)
}
offset += _BUCKETSIZE * etyp.size
gc = append(gc, _GC_END)
gc[0] = offset
gc[3] = uintptr(unsafe.Pointer(&gc[0])) // set self pointer
b := new(rtype)
b.size = offset
b.gc = unsafe.Pointer(&gc[0])
s := "bucket(" + *ktyp.string + "," + *etyp.string + ")"
b.string = &s
return b
}
// Take the GC program for "t" and append it to the GC program "gc".
func appendGCProgram(gc []uintptr, t *rtype) []uintptr {
p := t.gc
p = unsafe.Pointer(uintptr(p) + unsafe.Sizeof(uintptr(0))) // skip size
loop:
for {
var argcnt int
switch *(*uintptr)(p) {
case _GC_END:
// Note: _GC_END not included in append
break loop
case _GC_ARRAY_NEXT:
argcnt = 0
case _GC_APTR, _GC_STRING, _GC_EFACE, _GC_IFACE:
argcnt = 1
case _GC_PTR, _GC_CALL, _GC_CHAN_PTR, _GC_SLICE:
argcnt = 2
case _GC_ARRAY_START, _GC_REGION:
argcnt = 3
default:
panic("unknown GC program op for " + *t.string + ": " + strconv.FormatUint(*(*uint64)(p), 10))
}
for i := 0; i < argcnt+1; i++ {
gc = append(gc, *(*uintptr)(p))
p = unsafe.Pointer(uintptr(p) + unsafe.Sizeof(uintptr(0)))
}
}
return gc
}
func hMapOf(bucket *rtype) *rtype {
ptrsize := unsafe.Sizeof(uintptr(0))
// make gc program & compute hmap size
gc := make([]uintptr, 1) // first entry is size, filled in at the end
offset := unsafe.Sizeof(uint(0)) // count
offset += unsafe.Sizeof(uint32(0)) // flags
offset += unsafe.Sizeof(uint32(0)) // hash0
offset += unsafe.Sizeof(uint8(0)) // B
offset += unsafe.Sizeof(uint8(0)) // keysize
offset += unsafe.Sizeof(uint8(0)) // valuesize
offset = (offset + 1) / 2 * 2
offset += unsafe.Sizeof(uint16(0)) // bucketsize
offset = (offset + ptrsize - 1) / ptrsize * ptrsize
gc = append(gc, _GC_PTR, offset, uintptr(bucket.gc)) // buckets
offset += ptrsize
gc = append(gc, _GC_PTR, offset, uintptr(bucket.gc)) // oldbuckets
offset += ptrsize
offset += ptrsize // nevacuate
gc = append(gc, _GC_END)
gc[0] = offset
h := new(rtype)
h.size = offset
h.gc = unsafe.Pointer(&gc[0])
s := "hmap(" + *bucket.string + ")"
h.string = &s
return h
}
// garbage collection bytecode program for slice of non-zero-length values.
// See ../../cmd/gc/reflect.c:/^dgcsym1 and :/^dgcsym.
type sliceGC struct {
width uintptr // sizeof(slice)
op uintptr // _GC_SLICE
off uintptr // 0
elemgc unsafe.Pointer // element gc program
end uintptr // _GC_END
}
// garbage collection bytecode program for slice of zero-length values.
// See ../../cmd/gc/reflect.c:/^dgcsym1 and :/^dgcsym.
type sliceEmptyGC struct {
width uintptr // sizeof(slice)
op uintptr // _GC_APTR
off uintptr // 0
end uintptr // _GC_END
}
var sliceEmptyGCProg = sliceEmptyGC{
width: unsafe.Sizeof([]byte(nil)),
op: _GC_APTR,
off: 0,
end: _GC_END,
}
// SliceOf returns the slice type with element type t.
// For example, if t represents int, SliceOf(t) represents []int.
func SliceOf(t Type) Type {
typ := t.(*rtype)
// Look in cache.
ckey := cacheKey{Slice, typ, nil, 0}
if slice := cacheGet(ckey); slice != nil {
return slice
}
// Look in known types.
s := "[]" + *typ.string
for _, tt := range typesByString(s) {
slice := (*sliceType)(unsafe.Pointer(tt))
if slice.elem == typ {
return cachePut(ckey, tt)
}
}
// Make a slice type.
var islice interface{} = ([]unsafe.Pointer)(nil)
prototype := *(**sliceType)(unsafe.Pointer(&islice))
slice := new(sliceType)
*slice = *prototype
slice.string = &s
slice.hash = fnv1(typ.hash, '[')
slice.elem = typ
slice.uncommonType = nil
slice.ptrToThis = nil
slice.zero = unsafe.Pointer(&make([]byte, slice.size)[0])
if typ.size == 0 {
slice.gc = unsafe.Pointer(&sliceEmptyGCProg)
} else {
slice.gc = unsafe.Pointer(&sliceGC{
width: slice.size,
op: _GC_SLICE,
off: 0,
elemgc: typ.gc,
end: _GC_END,
})
}
// INCORRECT. Uncomment to check that TestSliceOfOfGC fails when slice.gc is wrong.
//slice.gc = unsafe.Pointer(&badGC{width: slice.size, end: _GC_END})
return cachePut(ckey, &slice.rtype)
}
// ArrayOf returns the array type with the given count and element type.
// For example, if t represents int, ArrayOf(5, t) represents [5]int.
//
// If the resulting type would be larger than the available address space,
// ArrayOf panics.
//
// TODO(rsc): Unexported for now. Export once the alg field is set correctly
// for the type. This may require significant work.
func arrayOf(count int, elem Type) Type {
typ := elem.(*rtype)
slice := SliceOf(elem)
// Look in cache.
ckey := cacheKey{Array, typ, nil, uintptr(count)}
if slice := cacheGet(ckey); slice != nil {
return slice
}
// Look in known types.
s := "[" + strconv.Itoa(count) + "]" + *typ.string
for _, tt := range typesByString(s) {
slice := (*sliceType)(unsafe.Pointer(tt))
if slice.elem == typ {
return cachePut(ckey, tt)
}
}
// Make an array type.
var iarray interface{} = [1]unsafe.Pointer{}
prototype := *(**arrayType)(unsafe.Pointer(&iarray))
array := new(arrayType)
*array = *prototype
array.string = &s
array.hash = fnv1(typ.hash, '[')
for n := uint32(count); n > 0; n >>= 8 {
array.hash = fnv1(array.hash, byte(n))
}
array.hash = fnv1(array.hash, ']')
array.elem = typ
max := ^uintptr(0) / typ.size
if uintptr(count) > max {
panic("reflect.ArrayOf: array size would exceed virtual address space")
}
array.size = typ.size * uintptr(count)
array.align = typ.align
array.fieldAlign = typ.fieldAlign
// TODO: array.alg
// TODO: array.gc
array.uncommonType = nil
array.ptrToThis = nil
array.zero = unsafe.Pointer(&make([]byte, array.size)[0])
array.len = uintptr(count)
array.slice = slice.(*rtype)
return cachePut(ckey, &array.rtype)
}
// toType converts from a *rtype to a Type that can be returned
// to the client of package reflect. In gc, the only concern is that
// a nil *rtype must be replaced by a nil Type, but in gccgo this
// function takes care of ensuring that multiple *rtype for the same
// type are coalesced into a single Type.
func toType(t *rtype) Type {
if t == nil {
return nil
}
return t
}
type layoutKey struct {
t *rtype // function signature
rcvr *rtype // receiver type, or nil if none
}
type layoutType struct {
t *rtype
argSize uintptr // size of arguments
retOffset uintptr // offset of return values.
}
var layoutCache struct {
sync.RWMutex
m map[layoutKey]layoutType
}
// funcLayout computes a struct type representing the layout of the
// function arguments and return values for the function type t.
// If rcvr != nil, rcvr specifies the type of the receiver.
// The returned type exists only for GC, so we only fill out GC relevant info.
// Currently, that's just size and the GC program. We also fill in
// the name for possible debugging use.
func funcLayout(t *rtype, rcvr *rtype) (frametype *rtype, argSize, retOffset uintptr) {
if t.Kind() != Func {
panic("reflect: funcLayout of non-func type")
}
if rcvr != nil && rcvr.Kind() == Interface {
panic("reflect: funcLayout with interface receiver " + rcvr.String())
}
k := layoutKey{t, rcvr}
layoutCache.RLock()
if x := layoutCache.m[k]; x.t != nil {
layoutCache.RUnlock()
return x.t, x.argSize, x.retOffset
}
layoutCache.RUnlock()
layoutCache.Lock()
if x := layoutCache.m[k]; x.t != nil {
layoutCache.Unlock()
return x.t, x.argSize, x.retOffset
}
tt := (*funcType)(unsafe.Pointer(t))
// compute gc program for arguments
gc := make([]uintptr, 1) // first entry is size, filled in at the end
offset := uintptr(0)
if rcvr != nil {
// Reflect uses the "interface" calling convention for
// methods, where receivers take one word of argument
// space no matter how big they actually are.
if rcvr.size > ptrSize {
// we pass a pointer to the receiver.
gc = append(gc, _GC_PTR, offset, uintptr(rcvr.gc))
} else if rcvr.pointers() {
// rcvr is a one-word pointer object. Its gc program
// is just what we need here.
gc = appendGCProgram(gc, rcvr)
}
offset += ptrSize
}
for _, arg := range tt.in {
offset = align(offset, uintptr(arg.align))
if arg.pointers() {
gc = append(gc, _GC_REGION, offset, arg.size, uintptr(arg.gc))
}
offset += arg.size
}
argSize = offset
if runtime.GOARCH == "amd64p32" {
offset = align(offset, 8)
}
offset = align(offset, ptrSize)
retOffset = offset
for _, res := range tt.out {
offset = align(offset, uintptr(res.align))
if res.pointers() {
gc = append(gc, _GC_REGION, offset, res.size, uintptr(res.gc))
}
offset += res.size
}
gc = append(gc, _GC_END)
gc[0] = offset
// build dummy rtype holding gc program
x := new(rtype)
x.size = offset
x.gc = unsafe.Pointer(&gc[0])
var s string
if rcvr != nil {
s = "methodargs(" + *rcvr.string + ")(" + *t.string + ")"
} else {
s = "funcargs(" + *t.string + ")"
}
x.string = &s
// cache result for future callers
if layoutCache.m == nil {
layoutCache.m = make(map[layoutKey]layoutType)
}
layoutCache.m[k] = layoutType{
t: x,
argSize: argSize,
retOffset: retOffset,
}
layoutCache.Unlock()
return x, argSize, retOffset
}