I found the comments of `findObject` in the runtime source:

```go
// findObject returns the base address for the heap object **containing**
// the address p, the object's span, and the index of the object in s.
// If p does not point into a heap object, it returns base == 0.
//
// If p points is an invalid heap pointer and debug.invalidptr != 0,
// findObject panics.
//
// refBase and refOff optionally give the base address of the object
// in which the pointer p was found and the byte offset at which it
// was found. These are used for error reporting.
//
// It is nosplit so it is safe for p to be a pointer to the current 
goroutine's stack.
// Since p is a uintptr, it would not be adjusted if the stack were to move.
//go:nosplit
func findObject(p, refBase, refOff uintptr) (base uintptr, s *mspan, 
objIndex uintptr)
```

On Sunday, February 6, 2022 at 10:33:35 AM UTC+8 rmfr wrote:

> It suddenly occurred to me that it was very like `re-slice` —— as long as 
> part of the underlying array is referenced, the whole underlying array is 
> never gc-ed. I guess there is a method in gc which could locate the whole 
> underlying array as long as one address inside the array's address interval 
> was provided? So now I tend to believe that `Element1` is correct too, and 
> the `underlyBuf` filed in `Element2` is redundant and is not quite 
> necessary, am I correct?
>
> On Sunday, February 6, 2022 at 10:08:06 AM UTC+8 rmfr wrote:
>
>> Please take a look at the following code:
>>
>> ```go
>> package main
>>
>> import (
>>     "fmt"
>>     "runtime"
>>     "unsafe"
>> )
>>
>> func assert(b bool) {
>>     if b {
>>     } else {
>>         panic("unexpected")
>>     }
>> }
>>
>> type Elementer interface {
>>     GetInt64Slice() []int64
>>     GetByteSlice() []byte
>>     String() string
>> }
>>
>> type Element1 struct {
>>     int64s []int64
>>     bs     []byte
>> }
>>
>> func newElement1(int64Sz, bsSz int) *Element1 {
>>     assert(int64Sz > 0 && bsSz > 0)
>>     len0 := int64Sz * 8
>>     len1 := bsSz
>>     buf := make([]byte, len0+len1)
>>     for i := range buf {
>>         buf[i] = byte(i)
>>     }
>>     e := &Element1{
>>         int64s: unsafe.Slice((*int64)(unsafe.Pointer(&buf[0])), int64Sz),
>>         bs:     unsafe.Slice((*byte)(&buf[len0]), bsSz),
>>     }
>>     return e
>> }
>>
>> func (e *Element1) GetInt64Slice() []int64 {
>>     return e.int64s
>> }
>>
>> func (e *Element1) GetByteSlice() []byte {
>>     return e.bs
>> }
>>
>> func (e *Element1) String() string {
>>     return fmt.Sprintf("Element1:[% x % x]", e.GetInt64Slice(), 
>> e.GetByteSlice())
>> }
>>
>> type Element2 struct {
>>     underlyBuf []byte  // <- is this field needed?
>>     int64s     []int64
>>     bs         []byte
>> }
>>
>> func newElement2(int64Sz, bsSz int) *Element2 {
>>     assert(int64Sz > 0 && bsSz > 0)
>>     len0 := int64Sz * 8
>>     len1 := bsSz
>>     buf := make([]byte, len0+len1)
>>     for i := range buf {
>>         buf[i] = byte(i)
>>     }
>>     e := &Element2{
>>         underlyBuf: buf,   // <-
>>         int64s:     unsafe.Slice((*int64)(unsafe.Pointer(&buf[0])), 
>> int64Sz),
>>         bs:         unsafe.Slice((*byte)(&buf[len0]), bsSz),
>>     }
>>     return e
>> }
>>
>> func (e *Element2) GetInt64Slice() []int64 {
>>     runtime.KeepAlive(e.underlyBuf)
>>     return e.int64s
>> }
>>
>> func (e *Element2) GetByteSlice() []byte {
>>     runtime.KeepAlive(e.underlyBuf)
>>     return e.bs
>> }
>>
>> func (e *Element2) String() string {
>>     runtime.KeepAlive(e.underlyBuf)
>>     return fmt.Sprintf("Element2:[% x % x]", e.GetInt64Slice(), 
>> e.GetByteSlice())
>> }
>>
>> func main() {
>>     var e Elementer
>>     fmt.Println("print with host endian:")
>>     e = newElement1(2, 4)
>>     fmt.Println("hi", e)
>>     e = newElement2(2, 4)
>>     fmt.Println("hi", e)
>> }
>> ```
>>
>> And which yields:
>>
>> ```
>> hi Element1:[[ 706050403020100  f0e0d0c0b0a0908] 10 11 12 13]
>> hi Element2:[[ 706050403020100  f0e0d0c0b0a0908] 10 11 12 13]
>> ```
>>
>> I'm not sure whether the `underlyBuf` filed in `Element2` is needed or 
>> not. When I'm reading the doc from `
>> https://pkg.go.dev/reflect#SliceHeader` 
>> <https://pkg.go.dev/reflect#SliceHeader> there is:
>>
>> > Moreover, the Data field is not sufficient to guarantee the data it 
>> references will not be garbage collected, so programs must keep a separate, 
>> correctly typed pointer to the underlying data.
>>
>> But in `https://pkg.go.dev/unsafe#Slice` 
>> <https://pkg.go.dev/unsafe#Slice> there are no such comments. So the 
>> question:
>>
>> Which implementation of `Elementer` is correct? `Element2` or both of 
>> them?
>>
>> Thanks a lot for your help.
>>
>

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/907d7b7f-303b-4f1f-a3ee-b51563ebdeb6n%40googlegroups.com.

Reply via email to