| // 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. |
| |
| // Runtime type representation. |
| |
| package runtime |
| |
| import ( |
| "runtime/internal/sys" |
| "unsafe" |
| ) |
| |
| // tflag is documented in ../reflect/type.go. |
| type tflag uint8 |
| |
| const tflagUncommon tflag = 1 |
| |
| // Needs to be in sync with ../cmd/compile/internal/ld/decodesym.go:/^func.commonsize, |
| // ../cmd/compile/internal/gc/reflect.go:/^func.dcommontype and |
| // ../reflect/type.go:/^type.rtype. |
| type _type struct { |
| size uintptr |
| ptrdata uintptr // size of memory prefix holding all pointers |
| hash uint32 |
| tflag tflag |
| align uint8 |
| fieldalign uint8 |
| kind uint8 |
| alg *typeAlg |
| // gcdata stores the GC type data for the garbage collector. |
| // If the KindGCProg bit is set in kind, gcdata is a GC program. |
| // Otherwise it is a ptrmask bitmap. See mbitmap.go for details. |
| gcdata *byte |
| _string string |
| } |
| |
| func (t *_type) uncommon() *uncommontype { |
| if t.tflag&tflagUncommon == 0 { |
| return nil |
| } |
| switch t.kind & kindMask { |
| case kindStruct: |
| type u struct { |
| structtype |
| u uncommontype |
| } |
| return &(*u)(unsafe.Pointer(t)).u |
| case kindPtr: |
| type u struct { |
| ptrtype |
| u uncommontype |
| } |
| return &(*u)(unsafe.Pointer(t)).u |
| case kindFunc: |
| type u struct { |
| functype |
| u uncommontype |
| } |
| return &(*u)(unsafe.Pointer(t)).u |
| case kindSlice: |
| type u struct { |
| slicetype |
| u uncommontype |
| } |
| return &(*u)(unsafe.Pointer(t)).u |
| case kindArray: |
| type u struct { |
| arraytype |
| u uncommontype |
| } |
| return &(*u)(unsafe.Pointer(t)).u |
| case kindChan: |
| type u struct { |
| chantype |
| u uncommontype |
| } |
| return &(*u)(unsafe.Pointer(t)).u |
| case kindMap: |
| type u struct { |
| maptype |
| u uncommontype |
| } |
| return &(*u)(unsafe.Pointer(t)).u |
| case kindInterface: |
| type u struct { |
| interfacetype |
| u uncommontype |
| } |
| return &(*u)(unsafe.Pointer(t)).u |
| default: |
| type u struct { |
| _type |
| u uncommontype |
| } |
| return &(*u)(unsafe.Pointer(t)).u |
| } |
| } |
| |
| func hasPrefix(s, prefix string) bool { |
| return len(s) >= len(prefix) && s[:len(prefix)] == prefix |
| } |
| |
| func (t *_type) name() string { |
| if hasPrefix(t._string, "map[") { |
| return "" |
| } |
| if hasPrefix(t._string, "struct {") { |
| return "" |
| } |
| if hasPrefix(t._string, "chan ") { |
| return "" |
| } |
| if hasPrefix(t._string, "chan<-") { |
| return "" |
| } |
| if hasPrefix(t._string, "func(") { |
| return "" |
| } |
| switch t._string[0] { |
| case '[', '*', '<': |
| return "" |
| } |
| i := len(t._string) - 1 |
| for i >= 0 { |
| if t._string[i] == '.' { |
| break |
| } |
| i-- |
| } |
| return t._string[i+1:] |
| } |
| |
| func (t *functype) in() []*_type { |
| // See funcType in reflect/type.go for details on data layout. |
| uadd := uintptr(unsafe.Sizeof(functype{})) |
| if t.typ.tflag&tflagUncommon != 0 { |
| uadd += unsafe.Sizeof(uncommontype{}) |
| } |
| return (*[1 << 20]*_type)(add(unsafe.Pointer(t), uadd))[:t.inCount] |
| } |
| |
| func (t *functype) out() []*_type { |
| // See funcType in reflect/type.go for details on data layout. |
| uadd := uintptr(unsafe.Sizeof(functype{})) |
| if t.typ.tflag&tflagUncommon != 0 { |
| uadd += unsafe.Sizeof(uncommontype{}) |
| } |
| outCount := t.outCount & (1<<15 - 1) |
| return (*[1 << 20]*_type)(add(unsafe.Pointer(t), uadd))[t.inCount : t.inCount+outCount] |
| } |
| |
| func (t *functype) dotdotdot() bool { |
| return t.outCount&(1<<15) != 0 |
| } |
| |
| type method struct { |
| name name |
| mtyp *_type |
| ifn unsafe.Pointer |
| tfn unsafe.Pointer |
| } |
| |
| type uncommontype struct { |
| pkgpath *string |
| mhdr []method |
| } |
| |
| type imethod struct { |
| name name |
| _type *_type |
| } |
| |
| type interfacetype struct { |
| typ _type |
| pkgpath *string |
| mhdr []imethod |
| } |
| |
| type maptype struct { |
| typ _type |
| key *_type |
| elem *_type |
| bucket *_type // internal type representing a hash bucket |
| hmap *_type // internal type representing a hmap |
| keysize uint8 // size of key slot |
| indirectkey bool // store ptr to key instead of key itself |
| valuesize uint8 // size of value slot |
| indirectvalue bool // store ptr to value instead of value itself |
| bucketsize uint16 // size of bucket |
| reflexivekey bool // true if k==k for all keys |
| needkeyupdate bool // true if we need to update key on an overwrite |
| } |
| |
| type arraytype struct { |
| typ _type |
| elem *_type |
| slice *_type |
| len uintptr |
| } |
| |
| type chantype struct { |
| typ _type |
| elem *_type |
| dir uintptr |
| } |
| |
| type slicetype struct { |
| typ _type |
| elem *_type |
| } |
| |
| type functype struct { |
| typ _type |
| inCount uint16 |
| outCount uint16 |
| } |
| |
| type ptrtype struct { |
| typ _type |
| elem *_type |
| } |
| |
| type structfield struct { |
| name name |
| typ *_type |
| offset uintptr |
| } |
| |
| type structtype struct { |
| typ _type |
| pkgPath *string |
| fields []structfield |
| } |
| |
| // name is an encoded type name with optional extra data. |
| // See reflect/type.go for details. |
| type name struct { |
| bytes *byte |
| } |
| |
| func (n *name) data(off int) *byte { |
| return (*byte)(add(unsafe.Pointer(n.bytes), uintptr(off))) |
| } |
| |
| func (n *name) isExported() bool { |
| return (*n.bytes)&(1<<0) != 0 |
| } |
| |
| func (n *name) nameLen() int { |
| return int(uint16(*n.data(1))<<8 | uint16(*n.data(2))) |
| } |
| |
| func (n *name) tagLen() int { |
| if *n.data(0)&(1<<1) == 0 { |
| return 0 |
| } |
| off := 3 + n.nameLen() |
| return int(uint16(*n.data(off))<<8 | uint16(*n.data(off + 1))) |
| } |
| |
| func (n *name) name() (s string) { |
| nl := n.nameLen() |
| if nl == 0 { |
| return "" |
| } |
| hdr := (*stringStruct)(unsafe.Pointer(&s)) |
| hdr.str = unsafe.Pointer(n.data(3)) |
| hdr.len = nl |
| return s |
| } |
| |
| func (n *name) pkgPath() *string { |
| if *n.data(0)&(1<<2) == 0 { |
| return nil |
| } |
| off := 3 + n.nameLen() |
| if tl := n.tagLen(); tl > 0 { |
| off += 2 + tl |
| } |
| off = int(round(uintptr(off), sys.PtrSize)) |
| return *(**string)(unsafe.Pointer(n.data(off))) |
| } |