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 224 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
235 String | 235 String |
236 Struct | 236 Struct |
237 UnsafePointer | 237 UnsafePointer |
238 ) | 238 ) |
239 | 239 |
240 // rtype is the common implementation of most values. | 240 // rtype is the common implementation of most values. |
241 // It is embedded in other, public struct types, but always | 241 // It is embedded in other, public struct types, but always |
242 // with a unique tag like `reflect:"array"` or `reflect:"ptr"` | 242 // with a unique tag like `reflect:"array"` or `reflect:"ptr"` |
243 // so that code cannot convert from, say, *arrayType to *ptrType. | 243 // so that code cannot convert from, say, *arrayType to *ptrType. |
244 type rtype struct { | 244 type rtype struct { |
245 » size uintptr // size in bytes | 245 » size uintptr // size in bytes |
246 » hash uint32 // hash of type; avoids computation in hash
tables | 246 » hash uint32 // hash of type; avoids computation in h
ash tables |
247 » _ uint8 // unused/padding | 247 » _ uint8 // unused/padding |
248 » align uint8 // alignment of variable with this type | 248 » align uint8 // alignment of variable with this type |
249 » fieldAlign uint8 // alignment of struct field with this type | 249 » fieldAlign uint8 // alignment of struct field with this t
ype |
250 » kind uint8 // enumeration for C | 250 » kind uint8 // enumeration for C |
251 » alg *uintptr // algorithm table (../runtime/runtime.h:/A
lg) | 251 » alg *uintptr // algorithm table (../runtime/runtime.h
:/Alg) |
252 » gc unsafe.Pointer // garbage collection data | 252 » gc [2]unsafe.Pointer // garbage collection data |
253 » string *string // string form; unnecessary but undeniably
useful | 253 » string *string // string form; unnecessary but undeniab
ly useful |
254 » *uncommonType // (relatively) uncommon fields | 254 » *uncommonType // (relatively) uncommon fields |
255 » ptrToThis *rtype // type for pointer to this type, if used i
n binary or has methods | 255 » ptrToThis *rtype // type for pointer to this type, if use
d in binary or has methods |
256 » zero unsafe.Pointer // pointer to zero value | 256 » zero unsafe.Pointer // pointer to zero value |
257 } | 257 } |
258 | 258 |
259 // Method on non-interface type | 259 // Method on non-interface type |
260 type method struct { | 260 type method struct { |
261 name *string // name of method | 261 name *string // name of method |
262 pkgPath *string // nil for exported Names; otherwise import path | 262 pkgPath *string // nil for exported Names; otherwise import path |
263 mtyp *rtype // method type (without receiver) | 263 mtyp *rtype // method type (without receiver) |
264 typ *rtype // .(*FuncType) underneath (with receiver) | 264 typ *rtype // .(*FuncType) underneath (with receiver) |
265 ifn unsafe.Pointer // fn used in interface call (one-word receiver) | 265 ifn unsafe.Pointer // fn used in interface call (one-word receiver) |
266 tfn unsafe.Pointer // fn used for normal method call | 266 tfn unsafe.Pointer // fn used for normal method call |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
350 tag *string // nil if no tag | 350 tag *string // nil if no tag |
351 offset uintptr // byte offset of field within struct | 351 offset uintptr // byte offset of field within struct |
352 } | 352 } |
353 | 353 |
354 // structType represents a struct type. | 354 // structType represents a struct type. |
355 type structType struct { | 355 type structType struct { |
356 rtype `reflect:"struct"` | 356 rtype `reflect:"struct"` |
357 fields []structField // sorted by offset | 357 fields []structField // sorted by offset |
358 } | 358 } |
359 | 359 |
360 // NOTE: These are copied from ../runtime/mgc0.h. | |
361 // They must be kept in sync. | |
362 const ( | |
363 _GC_END = iota | |
364 _GC_PTR | |
365 _GC_APTR | |
366 _GC_ARRAY_START | |
367 _GC_ARRAY_NEXT | |
368 _GC_CALL | |
369 _GC_CHAN_PTR | |
370 _GC_STRING | |
371 _GC_EFACE | |
372 _GC_IFACE | |
373 _GC_SLICE | |
374 _GC_REGION | |
375 _GC_NUM_INSTR | |
376 ) | |
377 | |
378 /* | 360 /* |
379 * The compiler knows the exact layout of all the data structures above. | 361 * The compiler knows the exact layout of all the data structures above. |
380 * The compiler does not know about the data structures and methods below. | 362 * The compiler does not know about the data structures and methods below. |
381 */ | 363 */ |
382 | 364 |
383 // Method represents a single method. | 365 // Method represents a single method. |
384 type Method struct { | 366 type Method struct { |
385 // Name is the method name. | 367 // Name is the method name. |
386 // PkgPath is the package path that qualifies a lower case (unexported) | 368 // PkgPath is the package path that qualifies a lower case (unexported) |
387 // method name. It is empty for upper case (exported) method names. | 369 // method name. It is empty for upper case (exported) method names. |
388 // The combination of PkgPath and Name uniquely identifies a method | 370 // The combination of PkgPath and Name uniquely identifies a method |
389 // in a method set. | 371 // in a method set. |
390 // See http://golang.org/ref/spec#Uniqueness_of_identifiers | 372 // See http://golang.org/ref/spec#Uniqueness_of_identifiers |
391 Name string | 373 Name string |
392 PkgPath string | 374 PkgPath string |
393 | 375 |
394 Type Type // method type | 376 Type Type // method type |
395 Func Value // func with receiver as first argument | 377 Func Value // func with receiver as first argument |
396 Index int // index for Type.Method | 378 Index int // index for Type.Method |
397 } | 379 } |
398 | 380 |
399 // High bit says whether type has | 381 // High bit says whether type has |
400 // embedded pointers,to help garbage collector. | 382 // embedded pointers,to help garbage collector. |
401 const ( | 383 const ( |
402 » kindMask = 0x7f | 384 » kindMask = 0x3f |
| 385 » kindGCProg = 0x40 |
403 kindNoPointers = 0x80 | 386 kindNoPointers = 0x80 |
404 ) | 387 ) |
405 | 388 |
406 func (k Kind) String() string { | 389 func (k Kind) String() string { |
407 if int(k) < len(kindNames) { | 390 if int(k) < len(kindNames) { |
408 return kindNames[k] | 391 return kindNames[k] |
409 } | 392 } |
410 return "kind" + strconv.Itoa(int(k)) | 393 return "kind" + strconv.Itoa(int(k)) |
411 } | 394 } |
412 | 395 |
(...skipping 593 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1006 eface := *(*emptyInterface)(unsafe.Pointer(&i)) | 989 eface := *(*emptyInterface)(unsafe.Pointer(&i)) |
1007 return toType(eface.typ) | 990 return toType(eface.typ) |
1008 } | 991 } |
1009 | 992 |
1010 // ptrMap is the cache for PtrTo. | 993 // ptrMap is the cache for PtrTo. |
1011 var ptrMap struct { | 994 var ptrMap struct { |
1012 sync.RWMutex | 995 sync.RWMutex |
1013 m map[*rtype]*ptrType | 996 m map[*rtype]*ptrType |
1014 } | 997 } |
1015 | 998 |
1016 // garbage collection bytecode program for pointer to memory without pointers. | |
1017 // See ../../cmd/gc/reflect.c:/^dgcsym1 and :/^dgcsym. | |
1018 type ptrDataGC struct { | |
1019 width uintptr // sizeof(ptr) | |
1020 op uintptr // _GC_APTR | |
1021 off uintptr // 0 | |
1022 end uintptr // _GC_END | |
1023 } | |
1024 | |
1025 var ptrDataGCProg = ptrDataGC{ | |
1026 width: unsafe.Sizeof((*byte)(nil)), | |
1027 op: _GC_APTR, | |
1028 off: 0, | |
1029 end: _GC_END, | |
1030 } | |
1031 | |
1032 // garbage collection bytecode program for pointer to memory with pointers. | |
1033 // See ../../cmd/gc/reflect.c:/^dgcsym1 and :/^dgcsym. | |
1034 type ptrGC struct { | |
1035 width uintptr // sizeof(ptr) | |
1036 op uintptr // _GC_PTR | |
1037 off uintptr // 0 | |
1038 elemgc unsafe.Pointer // element gc type | |
1039 end uintptr // _GC_END | |
1040 } | |
1041 | |
1042 // PtrTo returns the pointer type with element t. | 999 // PtrTo returns the pointer type with element t. |
1043 // For example, if t represents type Foo, PtrTo(t) represents *Foo. | 1000 // For example, if t represents type Foo, PtrTo(t) represents *Foo. |
1044 func PtrTo(t Type) Type { | 1001 func PtrTo(t Type) Type { |
1045 return t.(*rtype).ptrTo() | 1002 return t.(*rtype).ptrTo() |
1046 } | 1003 } |
1047 | 1004 |
1048 func (t *rtype) ptrTo() *rtype { | 1005 func (t *rtype) ptrTo() *rtype { |
1049 if p := t.ptrToThis; p != nil { | 1006 if p := t.ptrToThis; p != nil { |
1050 return p | 1007 return p |
1051 } | 1008 } |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1089 // Create a good hash for the new string by using | 1046 // Create a good hash for the new string by using |
1090 // the FNV-1 hash's mixing function to combine the | 1047 // the FNV-1 hash's mixing function to combine the |
1091 // old hash and the new "*". | 1048 // old hash and the new "*". |
1092 p.hash = fnv1(t.hash, '*') | 1049 p.hash = fnv1(t.hash, '*') |
1093 | 1050 |
1094 p.uncommonType = nil | 1051 p.uncommonType = nil |
1095 p.ptrToThis = nil | 1052 p.ptrToThis = nil |
1096 p.zero = unsafe.Pointer(&make([]byte, p.size)[0]) | 1053 p.zero = unsafe.Pointer(&make([]byte, p.size)[0]) |
1097 p.elem = t | 1054 p.elem = t |
1098 | 1055 |
1099 if t.kind&kindNoPointers != 0 { | |
1100 p.gc = unsafe.Pointer(&ptrDataGCProg) | |
1101 } else { | |
1102 p.gc = unsafe.Pointer(&ptrGC{ | |
1103 width: p.size, | |
1104 op: _GC_PTR, | |
1105 off: 0, | |
1106 elemgc: t.gc, | |
1107 end: _GC_END, | |
1108 }) | |
1109 } | |
1110 // INCORRECT. Uncomment to check that TestPtrToGC fails when p.gc is wro
ng. | |
1111 //p.gc = unsafe.Pointer(&badGC{width: p.size, end: _GC_END}) | |
1112 | |
1113 ptrMap.m[t] = p | 1056 ptrMap.m[t] = p |
1114 ptrMap.Unlock() | 1057 ptrMap.Unlock() |
1115 return &p.rtype | 1058 return &p.rtype |
1116 } | 1059 } |
1117 | 1060 |
1118 // fnv1 incorporates the list of bytes into the hash x using the FNV-1 hash func
tion. | 1061 // fnv1 incorporates the list of bytes into the hash x using the FNV-1 hash func
tion. |
1119 func fnv1(x uint32, list ...byte) uint32 { | 1062 func fnv1(x uint32, list ...byte) uint32 { |
1120 for _, b := range list { | 1063 for _, b := range list { |
1121 x = x*16777619 ^ uint32(b) | 1064 x = x*16777619 ^ uint32(b) |
1122 } | 1065 } |
(...skipping 284 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1407 | 1350 |
1408 // cachePut stores the given type in the cache, unlocks the cache, | 1351 // cachePut stores the given type in the cache, unlocks the cache, |
1409 // and returns the type. It is expected that the cache is locked | 1352 // and returns the type. It is expected that the cache is locked |
1410 // because cacheGet returned nil. | 1353 // because cacheGet returned nil. |
1411 func cachePut(k cacheKey, t *rtype) Type { | 1354 func cachePut(k cacheKey, t *rtype) Type { |
1412 lookupCache.m[k] = t | 1355 lookupCache.m[k] = t |
1413 lookupCache.Unlock() | 1356 lookupCache.Unlock() |
1414 return t | 1357 return t |
1415 } | 1358 } |
1416 | 1359 |
1417 // garbage collection bytecode program for chan. | |
1418 // See ../../cmd/gc/reflect.c:/^dgcsym1 and :/^dgcsym. | |
1419 type chanGC struct { | |
1420 width uintptr // sizeof(map) | |
1421 op uintptr // _GC_CHAN_PTR | |
1422 off uintptr // 0 | |
1423 typ *rtype // map type | |
1424 end uintptr // _GC_END | |
1425 } | |
1426 | |
1427 type badGC struct { | |
1428 width uintptr | |
1429 end uintptr | |
1430 } | |
1431 | |
1432 // ChanOf returns the channel type with the given direction and element type. | 1360 // ChanOf returns the channel type with the given direction and element type. |
1433 // For example, if t represents int, ChanOf(RecvDir, t) represents <-chan int. | 1361 // For example, if t represents int, ChanOf(RecvDir, t) represents <-chan int. |
1434 // | 1362 // |
1435 // The gc runtime imposes a limit of 64 kB on channel element types. | 1363 // The gc runtime imposes a limit of 64 kB on channel element types. |
1436 // If t's size is equal to or exceeds this limit, ChanOf panics. | 1364 // If t's size is equal to or exceeds this limit, ChanOf panics. |
1437 func ChanOf(dir ChanDir, t Type) Type { | 1365 func ChanOf(dir ChanDir, t Type) Type { |
1438 typ := t.(*rtype) | 1366 typ := t.(*rtype) |
1439 | 1367 |
1440 // Look in cache. | 1368 // Look in cache. |
1441 ckey := cacheKey{Chan, typ, nil, uintptr(dir)} | 1369 ckey := cacheKey{Chan, typ, nil, uintptr(dir)} |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1475 prototype := *(**chanType)(unsafe.Pointer(&ichan)) | 1403 prototype := *(**chanType)(unsafe.Pointer(&ichan)) |
1476 ch := new(chanType) | 1404 ch := new(chanType) |
1477 *ch = *prototype | 1405 *ch = *prototype |
1478 ch.string = &s | 1406 ch.string = &s |
1479 ch.hash = fnv1(typ.hash, 'c', byte(dir)) | 1407 ch.hash = fnv1(typ.hash, 'c', byte(dir)) |
1480 ch.elem = typ | 1408 ch.elem = typ |
1481 ch.uncommonType = nil | 1409 ch.uncommonType = nil |
1482 ch.ptrToThis = nil | 1410 ch.ptrToThis = nil |
1483 ch.zero = unsafe.Pointer(&make([]byte, ch.size)[0]) | 1411 ch.zero = unsafe.Pointer(&make([]byte, ch.size)[0]) |
1484 | 1412 |
1485 ch.gc = unsafe.Pointer(&chanGC{ | |
1486 width: ch.size, | |
1487 op: _GC_CHAN_PTR, | |
1488 off: 0, | |
1489 typ: &ch.rtype, | |
1490 end: _GC_END, | |
1491 }) | |
1492 | |
1493 // INCORRECT. Uncomment to check that TestChanOfGC fails when ch.gc is w
rong. | |
1494 //ch.gc = unsafe.Pointer(&badGC{width: ch.size, end: _GC_END}) | |
1495 | |
1496 return cachePut(ckey, &ch.rtype) | 1413 return cachePut(ckey, &ch.rtype) |
1497 } | 1414 } |
1498 | 1415 |
1499 func ismapkey(*rtype) bool // implemented in runtime | 1416 func ismapkey(*rtype) bool // implemented in runtime |
1500 | 1417 |
1501 // MapOf returns the map type with the given key and element types. | 1418 // MapOf returns the map type with the given key and element types. |
1502 // For example, if k represents int and e represents string, | 1419 // For example, if k represents int and e represents string, |
1503 // MapOf(k, e) represents map[int]string. | 1420 // MapOf(k, e) represents map[int]string. |
1504 // | 1421 // |
1505 // If the key type is not a valid map key type (that is, if it does | 1422 // If the key type is not a valid map key type (that is, if it does |
(...skipping 24 matching lines...) Expand all Loading... |
1530 // Make a map type. | 1447 // Make a map type. |
1531 var imap interface{} = (map[unsafe.Pointer]unsafe.Pointer)(nil) | 1448 var imap interface{} = (map[unsafe.Pointer]unsafe.Pointer)(nil) |
1532 prototype := *(**mapType)(unsafe.Pointer(&imap)) | 1449 prototype := *(**mapType)(unsafe.Pointer(&imap)) |
1533 mt := new(mapType) | 1450 mt := new(mapType) |
1534 *mt = *prototype | 1451 *mt = *prototype |
1535 mt.string = &s | 1452 mt.string = &s |
1536 mt.hash = fnv1(etyp.hash, 'm', byte(ktyp.hash>>24), byte(ktyp.hash>>16),
byte(ktyp.hash>>8), byte(ktyp.hash)) | 1453 mt.hash = fnv1(etyp.hash, 'm', byte(ktyp.hash>>24), byte(ktyp.hash>>16),
byte(ktyp.hash>>8), byte(ktyp.hash)) |
1537 mt.key = ktyp | 1454 mt.key = ktyp |
1538 mt.elem = etyp | 1455 mt.elem = etyp |
1539 mt.bucket = bucketOf(ktyp, etyp) | 1456 mt.bucket = bucketOf(ktyp, etyp) |
1540 mt.hmap = hMapOf(mt.bucket) | |
1541 mt.uncommonType = nil | 1457 mt.uncommonType = nil |
1542 mt.ptrToThis = nil | 1458 mt.ptrToThis = nil |
1543 mt.zero = unsafe.Pointer(&make([]byte, mt.size)[0]) | 1459 mt.zero = unsafe.Pointer(&make([]byte, mt.size)[0]) |
1544 mt.gc = unsafe.Pointer(&ptrGC{ | |
1545 width: unsafe.Sizeof(uintptr(0)), | |
1546 op: _GC_PTR, | |
1547 off: 0, | |
1548 elemgc: mt.hmap.gc, | |
1549 end: _GC_END, | |
1550 }) | |
1551 | |
1552 // INCORRECT. Uncomment to check that TestMapOfGC and TestMapOfGCValues | |
1553 // fail when mt.gc is wrong. | |
1554 //mt.gc = unsafe.Pointer(&badGC{width: mt.size, end: _GC_END}) | |
1555 | 1460 |
1556 return cachePut(ckey, &mt.rtype) | 1461 return cachePut(ckey, &mt.rtype) |
1557 } | 1462 } |
1558 | 1463 |
| 1464 // gcProg is a helper type for generatation of GC pointer info. |
| 1465 type gcProg struct { |
| 1466 gc []byte |
| 1467 size uintptr // size of type in bytes |
| 1468 } |
| 1469 |
| 1470 func (gc *gcProg) append(v byte) { |
| 1471 gc.align(unsafe.Sizeof(uintptr(0))) |
| 1472 gc.appendWord(v) |
| 1473 } |
| 1474 |
| 1475 // Appends t's type info to the current program. |
| 1476 func (gc *gcProg) appendProg(t *rtype) { |
| 1477 gc.align(uintptr(t.align)) |
| 1478 if !t.pointers() { |
| 1479 gc.size += t.size |
| 1480 return |
| 1481 } |
| 1482 nptr := t.size / unsafe.Sizeof(uintptr(0)) |
| 1483 var prog []byte |
| 1484 if t.kind&kindGCProg != 0 { |
| 1485 // Ensure that the runtime has unrolled GC program. |
| 1486 unsafe_New(t) |
| 1487 // The program is stored in t.gc[0], skip unroll flag. |
| 1488 prog = (*[1 << 30]byte)(unsafe.Pointer(t.gc[0]))[1:] |
| 1489 } else { |
| 1490 // The mask is embed directly in t.gc. |
| 1491 prog = (*[1 << 30]byte)(unsafe.Pointer(&t.gc[0]))[:] |
| 1492 } |
| 1493 for i := uintptr(0); i < nptr; i++ { |
| 1494 gc.appendWord(extractGCWord(prog, i)) |
| 1495 } |
| 1496 } |
| 1497 |
| 1498 func (gc *gcProg) appendWord(v byte) { |
| 1499 ptrsize := unsafe.Sizeof(uintptr(0)) |
| 1500 if gc.size%ptrsize != 0 { |
| 1501 panic("reflect: unaligned GC program") |
| 1502 } |
| 1503 nptr := gc.size / ptrsize |
| 1504 for uintptr(len(gc.gc)) < nptr/2+1 { |
| 1505 gc.gc = append(gc.gc, 0x44) // BitsScalar |
| 1506 } |
| 1507 gc.gc[nptr/2] &= ^(3 << ((nptr%2)*4 + 2)) |
| 1508 gc.gc[nptr/2] |= v << ((nptr%2)*4 + 2) |
| 1509 gc.size += ptrsize |
| 1510 } |
| 1511 |
| 1512 func (gc *gcProg) finalize() unsafe.Pointer { |
| 1513 if gc.size == 0 { |
| 1514 return nil |
| 1515 } |
| 1516 ptrsize := unsafe.Sizeof(uintptr(0)) |
| 1517 gc.align(ptrsize) |
| 1518 nptr := gc.size / ptrsize |
| 1519 for uintptr(len(gc.gc)) < nptr/2+1 { |
| 1520 gc.gc = append(gc.gc, 0x44) // BitsScalar |
| 1521 } |
| 1522 // If number of words is odd, repeat the mask twice. |
| 1523 // Compiler does the same. |
| 1524 if nptr%2 != 0 { |
| 1525 for i := uintptr(0); i < nptr; i++ { |
| 1526 gc.appendWord(extractGCWord(gc.gc, i)) |
| 1527 } |
| 1528 } |
| 1529 gc.gc = append([]byte{1}, gc.gc...) // prepend unroll flag |
| 1530 return unsafe.Pointer(&gc.gc[0]) |
| 1531 } |
| 1532 |
| 1533 func extractGCWord(gc []byte, i uintptr) byte { |
| 1534 return (gc[i/2] >> ((i%2)*4 + 2)) & 3 |
| 1535 } |
| 1536 |
| 1537 func (gc *gcProg) align(a uintptr) { |
| 1538 gc.size = align(gc.size, a) |
| 1539 } |
| 1540 |
| 1541 const ( |
| 1542 bitsScalar = 1 |
| 1543 bitsPointer = 2 |
| 1544 ) |
| 1545 |
1559 // Make sure these routines stay in sync with ../../pkg/runtime/hashmap.c! | 1546 // Make sure these routines stay in sync with ../../pkg/runtime/hashmap.c! |
1560 // These types exist only for GC, so we only fill out GC relevant info. | 1547 // These types exist only for GC, so we only fill out GC relevant info. |
1561 // Currently, that's just size and the GC program. We also fill in string | 1548 // Currently, that's just size and the GC program. We also fill in string |
1562 // for possible debugging use. | 1549 // for possible debugging use. |
1563 const ( | 1550 const ( |
1564 » _BUCKETSIZE = 8 | 1551 » bucketSize = 8 |
1565 » _MAXKEYSIZE = 128 | 1552 » maxKeySize = 128 |
1566 » _MAXVALSIZE = 128 | 1553 » maxValSize = 128 |
1567 ) | 1554 ) |
1568 | 1555 |
1569 func bucketOf(ktyp, etyp *rtype) *rtype { | 1556 func bucketOf(ktyp, etyp *rtype) *rtype { |
1570 » if ktyp.size > _MAXKEYSIZE { | 1557 » if ktyp.size > maxKeySize { |
1571 ktyp = PtrTo(ktyp).(*rtype) | 1558 ktyp = PtrTo(ktyp).(*rtype) |
1572 } | 1559 } |
1573 » if etyp.size > _MAXVALSIZE { | 1560 » if etyp.size > maxValSize { |
1574 etyp = PtrTo(etyp).(*rtype) | 1561 etyp = PtrTo(etyp).(*rtype) |
1575 } | 1562 } |
1576 ptrsize := unsafe.Sizeof(uintptr(0)) | 1563 ptrsize := unsafe.Sizeof(uintptr(0)) |
1577 | 1564 |
1578 » gc := make([]uintptr, 1) // first
entry is size, filled in at the end | 1565 » var gc gcProg |
1579 » offset := _BUCKETSIZE * unsafe.Sizeof(uint8(0)) // topbit
s | 1566 » // topbits |
1580 » gc = append(gc, _GC_PTR, offset, 0 /*self pointer set below*/) // overfl
ow | 1567 » for i := 0; i < int(bucketSize*unsafe.Sizeof(uint8(0))/ptrsize); i++ { |
1581 » offset += ptrsize | 1568 » » gc.append(bitsScalar) |
1582 | 1569 » } |
| 1570 » gc.append(bitsPointer) // overflow |
1583 if runtime.GOARCH == "amd64p32" { | 1571 if runtime.GOARCH == "amd64p32" { |
1584 » » offset += 4 | 1572 » » gc.append(bitsScalar) |
| 1573 » } |
| 1574 » // keys |
| 1575 » for i := 0; i < bucketSize; i++ { |
| 1576 » » gc.appendProg(ktyp) |
| 1577 » } |
| 1578 » // values |
| 1579 » for i := 0; i < bucketSize; i++ { |
| 1580 » » gc.appendProg(etyp) |
1585 } | 1581 } |
1586 | 1582 |
1587 // keys | |
1588 if ktyp.kind&kindNoPointers == 0 { | |
1589 gc = append(gc, _GC_ARRAY_START, offset, _BUCKETSIZE, ktyp.size) | |
1590 gc = appendGCProgram(gc, ktyp) | |
1591 gc = append(gc, _GC_ARRAY_NEXT) | |
1592 } | |
1593 offset += _BUCKETSIZE * ktyp.size | |
1594 | |
1595 // values | |
1596 if etyp.kind&kindNoPointers == 0 { | |
1597 gc = append(gc, _GC_ARRAY_START, offset, _BUCKETSIZE, etyp.size) | |
1598 gc = appendGCProgram(gc, etyp) | |
1599 gc = append(gc, _GC_ARRAY_NEXT) | |
1600 } | |
1601 offset += _BUCKETSIZE * etyp.size | |
1602 | |
1603 gc = append(gc, _GC_END) | |
1604 gc[0] = offset | |
1605 gc[3] = uintptr(unsafe.Pointer(&gc[0])) // set self pointer | |
1606 | |
1607 b := new(rtype) | 1583 b := new(rtype) |
1608 » b.size = offset | 1584 » b.size = gc.size |
1609 » b.gc = unsafe.Pointer(&gc[0]) | 1585 » b.gc[0] = gc.finalize() |
| 1586 » b.kind |= kindGCProg |
1610 s := "bucket(" + *ktyp.string + "," + *etyp.string + ")" | 1587 s := "bucket(" + *ktyp.string + "," + *etyp.string + ")" |
1611 b.string = &s | 1588 b.string = &s |
1612 return b | 1589 return b |
1613 } | 1590 } |
1614 | 1591 |
1615 // Take the GC program for "t" and append it to the GC program "gc". | |
1616 func appendGCProgram(gc []uintptr, t *rtype) []uintptr { | |
1617 p := t.gc | |
1618 p = unsafe.Pointer(uintptr(p) + unsafe.Sizeof(uintptr(0))) // skip size | |
1619 loop: | |
1620 for { | |
1621 var argcnt int | |
1622 switch *(*uintptr)(p) { | |
1623 case _GC_END: | |
1624 // Note: _GC_END not included in append | |
1625 break loop | |
1626 case _GC_ARRAY_NEXT: | |
1627 argcnt = 0 | |
1628 case _GC_APTR, _GC_STRING, _GC_EFACE, _GC_IFACE: | |
1629 argcnt = 1 | |
1630 case _GC_PTR, _GC_CALL, _GC_CHAN_PTR, _GC_SLICE: | |
1631 argcnt = 2 | |
1632 case _GC_ARRAY_START, _GC_REGION: | |
1633 argcnt = 3 | |
1634 default: | |
1635 panic("unknown GC program op for " + *t.string + ": " +
strconv.FormatUint(*(*uint64)(p), 10)) | |
1636 } | |
1637 for i := 0; i < argcnt+1; i++ { | |
1638 gc = append(gc, *(*uintptr)(p)) | |
1639 p = unsafe.Pointer(uintptr(p) + unsafe.Sizeof(uintptr(0)
)) | |
1640 } | |
1641 } | |
1642 return gc | |
1643 } | |
1644 func hMapOf(bucket *rtype) *rtype { | |
1645 ptrsize := unsafe.Sizeof(uintptr(0)) | |
1646 | |
1647 // make gc program & compute hmap size | |
1648 gc := make([]uintptr, 1) // first entry is size, filled in at
the end | |
1649 offset := unsafe.Sizeof(uint(0)) // count | |
1650 offset += unsafe.Sizeof(uint32(0)) // flags | |
1651 offset += unsafe.Sizeof(uint32(0)) // hash0 | |
1652 offset += unsafe.Sizeof(uint8(0)) // B | |
1653 offset += unsafe.Sizeof(uint8(0)) // keysize | |
1654 offset += unsafe.Sizeof(uint8(0)) // valuesize | |
1655 offset = (offset + 1) / 2 * 2 | |
1656 offset += unsafe.Sizeof(uint16(0)) // bucketsize | |
1657 offset = (offset + ptrsize - 1) / ptrsize * ptrsize | |
1658 gc = append(gc, _GC_PTR, offset, uintptr(bucket.gc)) // buckets | |
1659 offset += ptrsize | |
1660 gc = append(gc, _GC_PTR, offset, uintptr(bucket.gc)) // oldbuckets | |
1661 offset += ptrsize | |
1662 offset += ptrsize // nevacuate | |
1663 gc = append(gc, _GC_END) | |
1664 gc[0] = offset | |
1665 | |
1666 h := new(rtype) | |
1667 h.size = offset | |
1668 h.gc = unsafe.Pointer(&gc[0]) | |
1669 s := "hmap(" + *bucket.string + ")" | |
1670 h.string = &s | |
1671 return h | |
1672 } | |
1673 | |
1674 // garbage collection bytecode program for slice of non-zero-length values. | |
1675 // See ../../cmd/gc/reflect.c:/^dgcsym1 and :/^dgcsym. | |
1676 type sliceGC struct { | |
1677 width uintptr // sizeof(slice) | |
1678 op uintptr // _GC_SLICE | |
1679 off uintptr // 0 | |
1680 elemgc unsafe.Pointer // element gc program | |
1681 end uintptr // _GC_END | |
1682 } | |
1683 | |
1684 // garbage collection bytecode program for slice of zero-length values. | |
1685 // See ../../cmd/gc/reflect.c:/^dgcsym1 and :/^dgcsym. | |
1686 type sliceEmptyGC struct { | |
1687 width uintptr // sizeof(slice) | |
1688 op uintptr // _GC_APTR | |
1689 off uintptr // 0 | |
1690 end uintptr // _GC_END | |
1691 } | |
1692 | |
1693 var sliceEmptyGCProg = sliceEmptyGC{ | |
1694 width: unsafe.Sizeof([]byte(nil)), | |
1695 op: _GC_APTR, | |
1696 off: 0, | |
1697 end: _GC_END, | |
1698 } | |
1699 | |
1700 // SliceOf returns the slice type with element type t. | 1592 // SliceOf returns the slice type with element type t. |
1701 // For example, if t represents int, SliceOf(t) represents []int. | 1593 // For example, if t represents int, SliceOf(t) represents []int. |
1702 func SliceOf(t Type) Type { | 1594 func SliceOf(t Type) Type { |
1703 typ := t.(*rtype) | 1595 typ := t.(*rtype) |
1704 | 1596 |
1705 // Look in cache. | 1597 // Look in cache. |
1706 ckey := cacheKey{Slice, typ, nil, 0} | 1598 ckey := cacheKey{Slice, typ, nil, 0} |
1707 if slice := cacheGet(ckey); slice != nil { | 1599 if slice := cacheGet(ckey); slice != nil { |
1708 return slice | 1600 return slice |
1709 } | 1601 } |
(...skipping 12 matching lines...) Expand all Loading... |
1722 prototype := *(**sliceType)(unsafe.Pointer(&islice)) | 1614 prototype := *(**sliceType)(unsafe.Pointer(&islice)) |
1723 slice := new(sliceType) | 1615 slice := new(sliceType) |
1724 *slice = *prototype | 1616 *slice = *prototype |
1725 slice.string = &s | 1617 slice.string = &s |
1726 slice.hash = fnv1(typ.hash, '[') | 1618 slice.hash = fnv1(typ.hash, '[') |
1727 slice.elem = typ | 1619 slice.elem = typ |
1728 slice.uncommonType = nil | 1620 slice.uncommonType = nil |
1729 slice.ptrToThis = nil | 1621 slice.ptrToThis = nil |
1730 slice.zero = unsafe.Pointer(&make([]byte, slice.size)[0]) | 1622 slice.zero = unsafe.Pointer(&make([]byte, slice.size)[0]) |
1731 | 1623 |
1732 if typ.size == 0 { | |
1733 slice.gc = unsafe.Pointer(&sliceEmptyGCProg) | |
1734 } else { | |
1735 slice.gc = unsafe.Pointer(&sliceGC{ | |
1736 width: slice.size, | |
1737 op: _GC_SLICE, | |
1738 off: 0, | |
1739 elemgc: typ.gc, | |
1740 end: _GC_END, | |
1741 }) | |
1742 } | |
1743 | |
1744 // INCORRECT. Uncomment to check that TestSliceOfOfGC fails when slice.g
c is wrong. | |
1745 //slice.gc = unsafe.Pointer(&badGC{width: slice.size, end: _GC_END}) | |
1746 | |
1747 return cachePut(ckey, &slice.rtype) | 1624 return cachePut(ckey, &slice.rtype) |
1748 } | 1625 } |
1749 | 1626 |
1750 // ArrayOf returns the array type with the given count and element type. | 1627 // ArrayOf returns the array type with the given count and element type. |
1751 // For example, if t represents int, ArrayOf(5, t) represents [5]int. | 1628 // For example, if t represents int, ArrayOf(5, t) represents [5]int. |
1752 // | 1629 // |
1753 // If the resulting type would be larger than the available address space, | 1630 // If the resulting type would be larger than the available address space, |
1754 // ArrayOf panics. | 1631 // ArrayOf panics. |
1755 // | 1632 // |
1756 // TODO(rsc): Unexported for now. Export once the alg field is set correctly | 1633 // TODO(rsc): Unexported for now. Export once the alg field is set correctly |
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1854 layoutCache.RUnlock() | 1731 layoutCache.RUnlock() |
1855 layoutCache.Lock() | 1732 layoutCache.Lock() |
1856 if x := layoutCache.m[k]; x.t != nil { | 1733 if x := layoutCache.m[k]; x.t != nil { |
1857 layoutCache.Unlock() | 1734 layoutCache.Unlock() |
1858 return x.t, x.argSize, x.retOffset | 1735 return x.t, x.argSize, x.retOffset |
1859 } | 1736 } |
1860 | 1737 |
1861 tt := (*funcType)(unsafe.Pointer(t)) | 1738 tt := (*funcType)(unsafe.Pointer(t)) |
1862 | 1739 |
1863 // compute gc program for arguments | 1740 // compute gc program for arguments |
1864 » gc := make([]uintptr, 1) // first entry is size, filled in at the end | 1741 » var gc gcProg |
1865 » offset := uintptr(0) | |
1866 if rcvr != nil { | 1742 if rcvr != nil { |
1867 // Reflect uses the "interface" calling convention for | 1743 // Reflect uses the "interface" calling convention for |
1868 // methods, where receivers take one word of argument | 1744 // methods, where receivers take one word of argument |
1869 // space no matter how big they actually are. | 1745 // space no matter how big they actually are. |
1870 if rcvr.size > ptrSize { | 1746 if rcvr.size > ptrSize { |
1871 // we pass a pointer to the receiver. | 1747 // we pass a pointer to the receiver. |
1872 » » » gc = append(gc, _GC_PTR, offset, uintptr(rcvr.gc)) | 1748 » » » gc.append(bitsPointer) |
1873 } else if rcvr.pointers() { | 1749 } else if rcvr.pointers() { |
1874 // rcvr is a one-word pointer object. Its gc program | 1750 // rcvr is a one-word pointer object. Its gc program |
1875 // is just what we need here. | 1751 // is just what we need here. |
1876 » » » gc = appendGCProgram(gc, rcvr) | 1752 » » » gc.append(bitsPointer) |
| 1753 » » } else { |
| 1754 » » » gc.append(bitsScalar) |
1877 } | 1755 } |
1878 offset += ptrSize | |
1879 } | 1756 } |
1880 for _, arg := range tt.in { | 1757 for _, arg := range tt.in { |
1881 » » offset = align(offset, uintptr(arg.align)) | 1758 » » gc.appendProg(arg) |
1882 » » if arg.pointers() { | |
1883 » » » gc = append(gc, _GC_REGION, offset, arg.size, uintptr(ar
g.gc)) | |
1884 » » } | |
1885 » » offset += arg.size | |
1886 } | 1759 } |
1887 » argSize = offset | 1760 » argSize = gc.size |
1888 if runtime.GOARCH == "amd64p32" { | 1761 if runtime.GOARCH == "amd64p32" { |
1889 » » offset = align(offset, 8) | 1762 » » gc.align(8) |
1890 } | 1763 } |
1891 » offset = align(offset, ptrSize) | 1764 » gc.align(ptrSize) |
1892 » retOffset = offset | 1765 » retOffset = gc.size |
1893 for _, res := range tt.out { | 1766 for _, res := range tt.out { |
1894 » » offset = align(offset, uintptr(res.align)) | 1767 » » gc.appendProg(res) |
1895 » » if res.pointers() { | |
1896 » » » gc = append(gc, _GC_REGION, offset, res.size, uintptr(re
s.gc)) | |
1897 » » } | |
1898 » » offset += res.size | |
1899 } | 1768 } |
1900 » gc = append(gc, _GC_END) | 1769 » gc.align(ptrSize) |
1901 » gc[0] = offset | |
1902 | 1770 |
1903 // build dummy rtype holding gc program | 1771 // build dummy rtype holding gc program |
1904 x := new(rtype) | 1772 x := new(rtype) |
1905 » x.size = offset | 1773 » x.size = gc.size |
1906 » x.gc = unsafe.Pointer(&gc[0]) | 1774 » x.gc[0] = gc.finalize() |
| 1775 » x.kind |= kindGCProg |
1907 var s string | 1776 var s string |
1908 if rcvr != nil { | 1777 if rcvr != nil { |
1909 s = "methodargs(" + *rcvr.string + ")(" + *t.string + ")" | 1778 s = "methodargs(" + *rcvr.string + ")(" + *t.string + ")" |
1910 } else { | 1779 } else { |
1911 s = "funcargs(" + *t.string + ")" | 1780 s = "funcargs(" + *t.string + ")" |
1912 } | 1781 } |
1913 x.string = &s | 1782 x.string = &s |
1914 | 1783 |
1915 // cache result for future callers | 1784 // cache result for future callers |
1916 if layoutCache.m == nil { | 1785 if layoutCache.m == nil { |
1917 layoutCache.m = make(map[layoutKey]layoutType) | 1786 layoutCache.m = make(map[layoutKey]layoutType) |
1918 } | 1787 } |
1919 layoutCache.m[k] = layoutType{ | 1788 layoutCache.m[k] = layoutType{ |
1920 t: x, | 1789 t: x, |
1921 argSize: argSize, | 1790 argSize: argSize, |
1922 retOffset: retOffset, | 1791 retOffset: retOffset, |
1923 } | 1792 } |
1924 layoutCache.Unlock() | 1793 layoutCache.Unlock() |
1925 return x, argSize, retOffset | 1794 return x, argSize, retOffset |
1926 } | 1795 } |
OLD | NEW |