Skip to content

Commit

Permalink
Bring static pointers back to the static table (#48)
Browse files Browse the repository at this point in the history
When serializing a pointer to the static 256 entries uint64 table,
encode it as an offset into that table. Deserialize them by pointing
back at the static table.

This is a band-aid to fix
#44. Symptom was a `(int)
1` on the objects slice turning into `(int) 257`. I think there is a
deeper problem to be solved when two pointers point to the same address
but have different size, and the smaller one is encountered first. Maybe
time to create that intermediate representation to figure those out :)
  • Loading branch information
pelletier authored Sep 20, 2023
2 parents e1dfb73 + d280bc6 commit 2f0f5c7
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 0 deletions.
7 changes: 7 additions & 0 deletions internal/serde/reflect.go
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,13 @@ func serializePointedAt(s *Serializer, t reflect.Type, p unsafe.Pointer) {
return
}

if static(p) {
serializeVarint(s, -1)
off := staticOffset(p)
serializeVarint(s, off)
return
}

id, new := s.assignPointerID(p)
serializeVarint(s, int(id))
if !new {
Expand Down
9 changes: 9 additions & 0 deletions internal/serde/serde.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,15 @@ func newDeserializer(b []byte) *Deserializer {
func (d *Deserializer) readPtr() (unsafe.Pointer, sID) {
x, n := binary.Varint(d.b)
d.b = d.b[n:]

// pointer into static uint64 table
if x == -1 {
x, n = binary.Varint(d.b)
d.b = d.b[n:]
p := staticPointer(int(x))
return p, 0
}

i := sID(x)
p := d.ptrs[i]
return p, i
Expand Down
20 changes: 20 additions & 0 deletions internal/serde/unsafe.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,23 @@ func inlined(t reflect.Type) bool {
return false
}
}

var staticuint64s unsafe.Pointer

func init() {
zero := 0
var x interface{} = zero
staticuint64s = (*iface)(unsafe.Pointer(&x)).ptr
}

func static(p unsafe.Pointer) bool {
return uintptr(p) >= uintptr(staticuint64s) && uintptr(p) < uintptr(staticuint64s)+256
}

func staticOffset(p unsafe.Pointer) int {
return int(uintptr(p) - uintptr(staticuint64s))
}

func staticPointer(offset int) unsafe.Pointer {
return unsafe.Add(staticuint64s, offset)
}
10 changes: 10 additions & 0 deletions serde/serde_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,16 @@ func TestReflect(t *testing.T) {
})
}

func TestInt257(t *testing.T) {
one := 1
x := []any{
true,
one,
}
serde.RegisterType[[]any]()
assertRoundTrip(t, x)
}

func TestReflectCustom(t *testing.T) {
ser := func(s *serde.Serializer, x *int) error {
str := strconv.Itoa(*x)
Expand Down

0 comments on commit 2f0f5c7

Please sign in to comment.