In Go, the compiler needs to know the types of things when copying values

June 21, 2020

If Go implements generics (which seems likely to happen someday), there will be a lot of interesting generic functions that don't need to do much more with the specific types they're instantiated with other than copy values around (and often allocate slices and their backing arrays). The classical map, filter, and reduce trio all don't need to do anything more themselves than copy values, and the same is true for things like making a slice of the keys of a map. If the compiler is interested in generating only a single set of code for these generic functions (similar to how maps are implemented), one interesting question is how much it needs to know about the values being copied around here. In particular, does the Go runtime need to know their type, or is it enough to know how big they are and then just copy the relevant number of bytes with a memory move?

Unfortunately for us, the answer is that the Go runtime needs to know the types of the values it's copying, even if it's only copying them to already allocated memory. We can discover why by looking at the source for runtime.typedmemmove. The short version of why is that if the runtime is currently doing a garbage collection, all Go code needs to take special precautions when updating pointers. This includes when copying values that are either pointers or composite types that include pointers. When doing a bulk memory move, the runtime needs to know where the pointers are in the destination, and that requires knowing the type of the destination.

(For more, see runtime.bulkBarrierPreWrite.)

The Go runtime also needs to know the type of things when allocating memory for them (such as when creating or expanding a slice). This is because all newly allocated objects must have runtime information set up so that the Go garbage collector knows where any pointers in them are (among other things, this is why unsafe type conversions are still garbage collection safe). Setting up this information requires knowing the type of what is being allocated, because this information on pointers is in the type information.

The exception for both copying values and allocating new memory for them is that if the type contains no pointers, I believe that all the Go runtime needs to know is that and what alignment is required for values. A generic function could thus potentially be compiled into a general version for pointer containing types and a narrower version that only worked for non-pointer types. In practice you would probably just compile a version that was passed a pointer to the type information, because the type information gives you size, alignment, and pointer information all in one place with only a single argument.

(You'll notice that runtime.typedmemmove is just a memmove() if the type doesn't contain any pointers, although some of this is hidden in runtime.cgoCheckMemmove.)

Written on 21 June 2020.
« The additional complications in DNS updates that secondary DNS servers add
Today I learned that HTML <abbr> may not do much on mobile browsers »

Page tools: View Source, Add Comment.
Login: Password:
Atom Syndication: Recent Comments.

Last modified: Sun Jun 21 21:59:54 2020
This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.