In Go, the compiler needs to know the types of things when copying values
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
.)
|
|