Skip to content

Commit

Permalink
Make the casting/indirection clearer
Browse files Browse the repository at this point in the history
  • Loading branch information
chriso committed Nov 17, 2023
1 parent 9776dd2 commit b819413
Show file tree
Hide file tree
Showing 3 changed files with 17 additions and 11 deletions.
18 changes: 9 additions & 9 deletions types/reflect.go
Original file line number Diff line number Diff line change
Expand Up @@ -610,21 +610,18 @@ func deserializeStructFields(d *Deserializer, p unsafe.Pointer, n int, field fun
}

func serializeFunc(s *Serializer, t reflect.Type, p unsafe.Pointer) {
// p is a pointer to a function value, function values are pointers to a
// memory location starting with the address of the function, hence the
// double indirection here.
p = *(*unsafe.Pointer)(p)
if p == nil {
fn := *(**function)(p)
if fn == nil {
// Function IDs start at 1; use 0 to represent nil ptr.
serializeVarint(s, 0)
return
}

addr := *(*uintptr)(p)
id, closure := s.funcs.RegisterAddr(addr)
id, closure := s.funcs.RegisterAddr(fn.addr)
serializeVarint(s, int(id))

if closure != nil {
p = unsafe.Pointer(fn)
// Skip the first field, which is the function ptr.
serializeStructFields(s, p, closure.NumField()-1, func(i int) reflect.StructField {
return closure.Field(i + 1)
Expand All @@ -635,7 +632,7 @@ func serializeFunc(s *Serializer, t reflect.Type, p unsafe.Pointer) {
func deserializeFunc(d *Deserializer, t reflect.Type, p unsafe.Pointer) {
id := deserializeVarint(d)
if id == 0 {
*(**Func)(p) = nil
*(**function)(p) = nil
return
}

Expand All @@ -660,7 +657,10 @@ func deserializeFunc(d *Deserializer, t reflect.Type, p unsafe.Pointer) {

*(*unsafe.Pointer)(p) = closure
} else {
*(**Func)(p) = fn
// Avoid an allocation by storing a pointer to the immutable Func.
// This works because the addr is the first element in both the Func
// and function structs.
*(**function)(p) = (*function)(unsafe.Pointer(fn))
}
}

Expand Down
4 changes: 2 additions & 2 deletions types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -380,8 +380,8 @@ func (m *funcmap) ToFunc(id funcid) *Func {
return f
}

func (m *funcmap) RegisterAddr(addr uintptr) (id funcid, closureType reflect.Type) {
f := FuncByAddr(addr)
func (m *funcmap) RegisterAddr(addr unsafe.Pointer) (id funcid, closureType reflect.Type) {
f := FuncByAddr(uintptr(addr))
if f == nil {
panic(fmt.Sprintf("function not found at address %v", addr))
}
Expand Down
6 changes: 6 additions & 0 deletions types/unsafe.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ type slice struct {
cap int
}

// Used for unsafe access to a function pointer and closure vars.
type function struct {
addr unsafe.Pointer
// closure vars follow...
}

// returns true iff type t would be inlined in an interface.
func inlined(t reflect.Type) bool {
switch t.Kind() {
Expand Down

0 comments on commit b819413

Please sign in to comment.