Skip to content

Roadmap

Ayke edited this page Dec 10, 2018 · 4 revisions

Also see the wishlist for features more distant in the future.

Standard library

The standard library is already supported, but because some features of Go are not yet fully supported many packages fail to compile. Fixing this is done with the following steps:

  1. Try to use a package you want to see supported.
  2. See what language feature or stdlib feature is not implemented yet.
  3. Add support for it in TinyGo, possibly stubbing it out for now (like most of reflect currently is).
  4. Does the package compile? Great, you're done (if it also runs correctly). If not, repeat from step 1.

Cgo support

Almost ready at the time of writing, see PR #89. Not all features from gc are supported. If you want to add support for more features, these are the locations where you'll have to take a look:

  • loader/libclang.go for the lower level libclang plumbing. This file uses libclang directly to parse the import "C" preamble and extracts type/function information from it.
  • loader/cgo.go for high level Cgo support. This file modifies the Go AST based on the information loaded from libclang.

Reflection

Reflection is huge. Most likely this will need to be broken into smaller steps because doing it all at once is just too big. Reflection is intimately related to interface support, which you can read about in this blog post.

At the moment interface support is broken into two steps: writing some special code in IR and a later step that lowers this special IR into regular IR constructs. At the moment, a type is considered unique if it has the same string representation (see Type.String()). Apart from causing bugs like issue #83, type information should be preserved in a more structured way for the later lowering pass.

The central part of reflection is of course determining what type any given interface has, in a more general way than type switches / type asserts provide. To support this, Go has the notion of a type kind, which is in what category a type falls. Examples are int, uint, uint8, pointer, struct, slice, channel, unsafe pointer. Also important are named types, which are distinct from their bare types (like int). And then there are type aliases, which are not distinct from the types they alias, leading to bugs like #83.

This is one possible implementation strategy for reflection:

  • The type code (which is a uintptr and is part of an interface) is broken up into a type kind and a more specific type. The lowest 5 bits are for the type kind as 5 bits are enough to identify the 25 different type kinds. The upper bits (27 bits on a 32-bit CPU) are used to uniquely identify a particular type within a type kind.
  • All named types are perhaps considered a type kind in this system, so that the upper 27 bits contain the real type kind and the rest of the type ID of this type, leaving 22 bits for the specific type.
  • Perhaps the number of bits for the type kind can be reduced to use less bits when few type kinds are in use. If less than 16 are in use, only 4 bits need to be used. However, such a thing introduces more complications and may not save that much in practice.
  • Some types like channels, pointers and slices could be stored in the same way. Bit 0..4 store the fact that they are a channel (etc.), bit 5..31 store the type ID of the thing they contain. So for example a channel sending integer pointers (chan *int) would have bit 0..4 set to the type kind of channel, bit 5..9 would be set to the type kind of pointer, and the rest is zero because this is a plain integer.
    This strategy may be problematic because it uses lots of bits, perhaps a single pointer-sized integer (as is currently used) is not big enough, especially on the AVR where a 16-bit integer is used.
  • Types like struct, func, etc. may be implemented using a side table that contains the elements of their type. Unfortunately, a struct can have any number of elements so must be stored separately somehow.
Clone this wiki locally