Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(504)

Side by Side Diff: src/pkg/reflect/type.go

Issue 106260045: code review 106260045: runtime: simpler and faster GC (Closed)
Patch Set: diff -r d4f4fb0e307c https://dvyukov%40google.com@code.google.com/p/go/ Created 9 years, 8 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/cmd/ld/lib.h ('k') | src/pkg/runtime/chan.goc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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
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
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 }
OLDNEW
« no previous file with comments | « src/cmd/ld/lib.h ('k') | src/pkg/runtime/chan.goc » ('j') | no next file with comments »

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b