Skip to content

Commit

Permalink
Avoid ArrayOf for strings/slices on serialization path
Browse files Browse the repository at this point in the history
  • Loading branch information
chriso committed Nov 23, 2023
1 parent db5da01 commit 351e691
Show file tree
Hide file tree
Showing 6 changed files with 118 additions and 44 deletions.
50 changes: 33 additions & 17 deletions gen/proto/go/coroutine/v1/coroutine.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

29 changes: 28 additions & 1 deletion gen/proto/go/coroutine/v1/coroutine_vtproto.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 9 additions & 1 deletion proto/coroutine/v1/coroutine.proto
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,14 @@ message Region {
// Type is the type of the region.
uint32 type = 1;

// Array length, when >= 0, indicates that this region is an
// array of the specified length (in terms of number of
// elements, not in terms of bytes) and that the region type
// is the type of the array element. If the array length is < 0
// then this region does not represent an array, and the region
// type describes the object that is encoded.
int32 array_length = 2;

// Data is the encoded contents of the memory region.
bytes data = 2;
bytes data = 3;
}
32 changes: 22 additions & 10 deletions types/inspect.go
Original file line number Diff line number Diff line change
Expand Up @@ -598,7 +598,27 @@ func (t *Region) Index() int {

// Type is the type of the region.
func (r *Region) Type() *Type {
return r.state.Type(int(r.region.Type - 1))
t := r.state.Type(int(r.region.Type - 1))
if r.region.ArrayLength >= 0 {
t = newArrayType(r.state, int64(r.region.ArrayLength), t)
}
return t
}

func newArrayType(state *State, length int64, t *Type) *Type {
idx := t.Index()
if idx < 0 {
panic("BUG")
}
return &Type{
state: state,
typ: &coroutinev1.Type{
Kind: coroutinev1.Kind_KIND_ARRAY,
Length: int64(length),
Elem: uint32(idx + 1),
},
index: -1, // aka. a derived type
}
}

// Size is the size of the region in bytes.
Expand Down Expand Up @@ -967,15 +987,7 @@ func (s *Scanner) readType() (ok bool) {
return false
}
if len >= 0 {
t = &Type{
state: s.state,
typ: &coroutinev1.Type{
Kind: coroutinev1.Kind_KIND_ARRAY,
Length: len,
Elem: t.typ.Elem,
},
index: -1,
}
t = newArrayType(s.state, len, t)
}
s.typ = t
return true
Expand Down
36 changes: 23 additions & 13 deletions types/reflect.go
Original file line number Diff line number Diff line change
Expand Up @@ -394,11 +394,7 @@ func serializePointedAt(s *Serializer, et reflect.Type, length int, p unsafe.Poi
r.len = length
}

if r.len >= 0 {
r.typ = reflect.ArrayOf(r.len, r.typ)
}

if r.typ.Kind() == reflect.Map {
if r.len < 0 && r.typ.Kind() == reflect.Map {
serializeMap(s, r.typ, r.addr)
return
}
Expand All @@ -414,20 +410,29 @@ func serializePointedAt(s *Serializer, et reflect.Type, length int, p unsafe.Poi
}

region := &coroutinev1.Region{
Type: s.types.ToType(r.typ),
Type: s.types.ToType(r.typ),
ArrayLength: int32(r.len),
}
s.regions = append(s.regions, region)

if r.typ.Kind() == reflect.Array && r.typ.Elem().Kind() == reflect.Uint8 {
// Fast path for byte arrays.
if n := r.typ.Len(); n > 0 {
region.Data = unsafe.Slice((*byte)(r.addr), n)
// Fast path for byte arrays.
if r.len >= 0 && r.typ.Kind() == reflect.Uint8 {
if r.len >= 0 {
region.Data = unsafe.Slice((*byte)(r.addr), r.len)
}
return
}

regionSer := s.fork()
if r.len >= 0 { // array
es := int(r.typ.Size())
for i := 0; i < r.len; i++ {
serializeAny(regionSer, r.typ, unsafe.Add(r.addr, i*es))
}
} else {
regionSer := s.fork()
serializeAny(regionSer, r.typ, r.addr)
region.Data = regionSer.b
}
region.Data = regionSer.b
}

func deserializePointedAt(d *Deserializer, et reflect.Type, length int) reflect.Value {
Expand Down Expand Up @@ -471,6 +476,10 @@ func deserializePointedAt(d *Deserializer, et reflect.Type, length int) reflect.

regionType := d.types.ToReflect(typeid(region.Type))

if region.ArrayLength >= 0 {
regionType = reflect.ArrayOf(int(region.ArrayLength), regionType)
}

container := reflect.New(regionType)
p = container.UnsafePointer()
d.store(sID(id), p)
Expand Down Expand Up @@ -514,7 +523,8 @@ func serializeMapReflect(s *Serializer, t reflect.Type, r reflect.Value) {
size := r.Len()

region := &coroutinev1.Region{
Type: s.types.ToType(t),
Type: s.types.ToType(t),
ArrayLength: -1, // not an array
}
s.regions = append(s.regions, region)

Expand Down
5 changes: 3 additions & 2 deletions types/serde.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,9 @@ func Serialize(x any) ([]byte, error) {
Strings: s.strings.strings,
Regions: s.regions,
Root: &coroutinev1.Region{
Type: s.types.ToType(t),
Data: s.b,
Type: s.types.ToType(t),
ArrayLength: -1, // not an array
Data: s.b,
},
}
return state.MarshalVT()
Expand Down

0 comments on commit 351e691

Please sign in to comment.