OLD | NEW |
1 // Copyright 2009 The Go Authors. All rights reserved. | 1 // Copyright 2009 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 // Package reflect implements run-time reflection, allowing a program to | 5 // Package reflect implements run-time reflection, allowing a program to |
6 // manipulate objects with arbitrary types. The typical use is to take a value | 6 // manipulate objects with arbitrary types. The typical use is to take a value |
7 // with static type interface{} and extract its dynamic type information by | 7 // with static type interface{} and extract its dynamic type information by |
8 // calling TypeOf, which returns a Type. | 8 // calling TypeOf, which returns a Type. |
9 // | 9 // |
10 // A call to ValueOf returns a Value representing the run-time data. | 10 // A call to ValueOf returns a Value representing the run-time data. |
(...skipping 365 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
376 // in a method set. | 376 // in a method set. |
377 // See http://golang.org/ref/spec#Uniqueness_of_identifiers | 377 // See http://golang.org/ref/spec#Uniqueness_of_identifiers |
378 Name string | 378 Name string |
379 PkgPath string | 379 PkgPath string |
380 | 380 |
381 Type Type // method type | 381 Type Type // method type |
382 Func Value // func with receiver as first argument | 382 Func Value // func with receiver as first argument |
383 Index int // index for Type.Method | 383 Index int // index for Type.Method |
384 } | 384 } |
385 | 385 |
386 // High bit says whether type has | |
387 // embedded pointers,to help garbage collector. | |
388 const ( | 386 const ( |
389 » kindMask = 0x3f | 387 » kindDirectIface = 1 << 5 |
390 » kindGCProg = 0x40 | 388 » kindGCProg = 1 << 6 // Type.gc points to GC program |
391 » kindNoPointers = 0x80 | 389 » kindNoPointers = 1 << 7 |
| 390 » kindMask = (1 << 5) - 1 |
392 ) | 391 ) |
393 | 392 |
394 func (k Kind) String() string { | 393 func (k Kind) String() string { |
395 if int(k) < len(kindNames) { | 394 if int(k) < len(kindNames) { |
396 return kindNames[k] | 395 return kindNames[k] |
397 } | 396 } |
398 return "kind" + strconv.Itoa(int(k)) | 397 return "kind" + strconv.Itoa(int(k)) |
399 } | 398 } |
400 | 399 |
401 var kindNames = []string{ | 400 var kindNames = []string{ |
(...skipping 1094 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1496 func (gc *gcProg) appendProg(t *rtype) { | 1495 func (gc *gcProg) appendProg(t *rtype) { |
1497 gc.align(uintptr(t.align)) | 1496 gc.align(uintptr(t.align)) |
1498 if !t.pointers() { | 1497 if !t.pointers() { |
1499 gc.size += t.size | 1498 gc.size += t.size |
1500 return | 1499 return |
1501 } | 1500 } |
1502 nptr := t.size / unsafe.Sizeof(uintptr(0)) | 1501 nptr := t.size / unsafe.Sizeof(uintptr(0)) |
1503 var prog []byte | 1502 var prog []byte |
1504 if t.kind&kindGCProg != 0 { | 1503 if t.kind&kindGCProg != 0 { |
1505 // Ensure that the runtime has unrolled GC program. | 1504 // Ensure that the runtime has unrolled GC program. |
| 1505 // TODO(rsc): Do not allocate. |
1506 unsafe_New(t) | 1506 unsafe_New(t) |
1507 // The program is stored in t.gc[0], skip unroll flag. | 1507 // The program is stored in t.gc[0], skip unroll flag. |
1508 prog = (*[1 << 30]byte)(unsafe.Pointer(t.gc[0]))[1:] | 1508 prog = (*[1 << 30]byte)(unsafe.Pointer(t.gc[0]))[1:] |
1509 } else { | 1509 } else { |
1510 // The mask is embed directly in t.gc. | 1510 // The mask is embed directly in t.gc. |
1511 prog = (*[1 << 30]byte)(unsafe.Pointer(&t.gc[0]))[:] | 1511 prog = (*[1 << 30]byte)(unsafe.Pointer(&t.gc[0]))[:] |
1512 } | 1512 } |
1513 for i := uintptr(0); i < nptr; i++ { | 1513 for i := uintptr(0); i < nptr; i++ { |
1514 gc.appendWord(extractGCWord(prog, i)) | 1514 gc.appendWord(extractGCWord(prog, i)) |
1515 } | 1515 } |
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1645 } | 1645 } |
1646 | 1646 |
1647 // ArrayOf returns the array type with the given count and element type. | 1647 // ArrayOf returns the array type with the given count and element type. |
1648 // For example, if t represents int, ArrayOf(5, t) represents [5]int. | 1648 // For example, if t represents int, ArrayOf(5, t) represents [5]int. |
1649 // | 1649 // |
1650 // If the resulting type would be larger than the available address space, | 1650 // If the resulting type would be larger than the available address space, |
1651 // ArrayOf panics. | 1651 // ArrayOf panics. |
1652 // | 1652 // |
1653 // TODO(rsc): Unexported for now. Export once the alg field is set correctly | 1653 // TODO(rsc): Unexported for now. Export once the alg field is set correctly |
1654 // for the type. This may require significant work. | 1654 // for the type. This may require significant work. |
| 1655 // |
| 1656 // TODO(rsc): TestArrayOf is also disabled. Re-enable. |
1655 func arrayOf(count int, elem Type) Type { | 1657 func arrayOf(count int, elem Type) Type { |
1656 typ := elem.(*rtype) | 1658 typ := elem.(*rtype) |
1657 slice := SliceOf(elem) | 1659 slice := SliceOf(elem) |
1658 | 1660 |
1659 // Look in cache. | 1661 // Look in cache. |
1660 ckey := cacheKey{Array, typ, nil, uintptr(count)} | 1662 ckey := cacheKey{Array, typ, nil, uintptr(count)} |
1661 if slice := cacheGet(ckey); slice != nil { | 1663 if slice := cacheGet(ckey); slice != nil { |
1662 return slice | 1664 return slice |
1663 } | 1665 } |
1664 | 1666 |
1665 // Look in known types. | 1667 // Look in known types. |
1666 s := "[" + strconv.Itoa(count) + "]" + *typ.string | 1668 s := "[" + strconv.Itoa(count) + "]" + *typ.string |
1667 for _, tt := range typesByString(s) { | 1669 for _, tt := range typesByString(s) { |
1668 slice := (*sliceType)(unsafe.Pointer(tt)) | 1670 slice := (*sliceType)(unsafe.Pointer(tt)) |
1669 if slice.elem == typ { | 1671 if slice.elem == typ { |
1670 return cachePut(ckey, tt) | 1672 return cachePut(ckey, tt) |
1671 } | 1673 } |
1672 } | 1674 } |
1673 | 1675 |
1674 // Make an array type. | 1676 // Make an array type. |
1675 var iarray interface{} = [1]unsafe.Pointer{} | 1677 var iarray interface{} = [1]unsafe.Pointer{} |
1676 prototype := *(**arrayType)(unsafe.Pointer(&iarray)) | 1678 prototype := *(**arrayType)(unsafe.Pointer(&iarray)) |
1677 array := new(arrayType) | 1679 array := new(arrayType) |
1678 *array = *prototype | 1680 *array = *prototype |
| 1681 // TODO: Set extra kind bits correctly. |
1679 array.string = &s | 1682 array.string = &s |
1680 array.hash = fnv1(typ.hash, '[') | 1683 array.hash = fnv1(typ.hash, '[') |
1681 for n := uint32(count); n > 0; n >>= 8 { | 1684 for n := uint32(count); n > 0; n >>= 8 { |
1682 array.hash = fnv1(array.hash, byte(n)) | 1685 array.hash = fnv1(array.hash, byte(n)) |
1683 } | 1686 } |
1684 array.hash = fnv1(array.hash, ']') | 1687 array.hash = fnv1(array.hash, ']') |
1685 array.elem = typ | 1688 array.elem = typ |
1686 max := ^uintptr(0) / typ.size | 1689 max := ^uintptr(0) / typ.size |
1687 if uintptr(count) > max { | 1690 if uintptr(count) > max { |
1688 panic("reflect.ArrayOf: array size would exceed virtual address
space") | 1691 panic("reflect.ArrayOf: array size would exceed virtual address
space") |
1689 } | 1692 } |
1690 array.size = typ.size * uintptr(count) | 1693 array.size = typ.size * uintptr(count) |
1691 array.align = typ.align | 1694 array.align = typ.align |
1692 array.fieldAlign = typ.fieldAlign | 1695 array.fieldAlign = typ.fieldAlign |
1693 // TODO: array.alg | 1696 // TODO: array.alg |
1694 // TODO: array.gc | 1697 // TODO: array.gc |
| 1698 // TODO: |
1695 array.uncommonType = nil | 1699 array.uncommonType = nil |
1696 array.ptrToThis = nil | 1700 array.ptrToThis = nil |
1697 array.zero = unsafe.Pointer(&make([]byte, array.size)[0]) | 1701 array.zero = unsafe.Pointer(&make([]byte, array.size)[0]) |
1698 array.len = uintptr(count) | 1702 array.len = uintptr(count) |
1699 array.slice = slice.(*rtype) | 1703 array.slice = slice.(*rtype) |
1700 | 1704 |
1701 return cachePut(ckey, &array.rtype) | 1705 return cachePut(ckey, &array.rtype) |
1702 } | 1706 } |
1703 | 1707 |
1704 // toType converts from a *rtype to a Type that can be returned | 1708 // toType converts from a *rtype to a Type that can be returned |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1756 } | 1760 } |
1757 | 1761 |
1758 tt := (*funcType)(unsafe.Pointer(t)) | 1762 tt := (*funcType)(unsafe.Pointer(t)) |
1759 | 1763 |
1760 // compute gc program for arguments | 1764 // compute gc program for arguments |
1761 var gc gcProg | 1765 var gc gcProg |
1762 if rcvr != nil { | 1766 if rcvr != nil { |
1763 // Reflect uses the "interface" calling convention for | 1767 // Reflect uses the "interface" calling convention for |
1764 // methods, where receivers take one word of argument | 1768 // methods, where receivers take one word of argument |
1765 // space no matter how big they actually are. | 1769 // space no matter how big they actually are. |
1766 » » if rcvr.size > ptrSize { | 1770 » » if !isDirectIface(rcvr) { |
1767 // we pass a pointer to the receiver. | 1771 // we pass a pointer to the receiver. |
1768 gc.append(bitsPointer) | 1772 gc.append(bitsPointer) |
1769 } else if rcvr.pointers() { | 1773 } else if rcvr.pointers() { |
1770 // rcvr is a one-word pointer object. Its gc program | 1774 // rcvr is a one-word pointer object. Its gc program |
1771 // is just what we need here. | 1775 // is just what we need here. |
1772 gc.append(bitsPointer) | 1776 gc.append(bitsPointer) |
1773 } else { | 1777 } else { |
1774 gc.append(bitsScalar) | 1778 gc.append(bitsScalar) |
1775 } | 1779 } |
1776 } | 1780 } |
(...skipping 29 matching lines...) Expand all Loading... |
1806 layoutCache.m = make(map[layoutKey]layoutType) | 1810 layoutCache.m = make(map[layoutKey]layoutType) |
1807 } | 1811 } |
1808 layoutCache.m[k] = layoutType{ | 1812 layoutCache.m[k] = layoutType{ |
1809 t: x, | 1813 t: x, |
1810 argSize: argSize, | 1814 argSize: argSize, |
1811 retOffset: retOffset, | 1815 retOffset: retOffset, |
1812 } | 1816 } |
1813 layoutCache.Unlock() | 1817 layoutCache.Unlock() |
1814 return x, argSize, retOffset | 1818 return x, argSize, retOffset |
1815 } | 1819 } |
| 1820 |
| 1821 // isDirectIface reports whether t is stored directly in an interface value. |
| 1822 func isDirectIface(t *rtype) bool { |
| 1823 return t.kind&kindDirectIface != 0 |
| 1824 } |
OLD | NEW |