The strategy here is to reuse the fact that require is already thread safe. This means we keep the autoload around and when a constant is defined, we add it to the autoload itself. Only the currently loading thread will see that constant for code loading. Other threads will still see the Autoload and try to load the file, this blocking until the loading is done and continue afterwards.
In the Autoload parts in the VM we now do the lookup again so it's much easier to do it with the correct current scope and we follow the same lookup mechanisms as a normal constant lookup. For this we modify the Helpers for const_get so it can filter a result so the autoload is filtered and the real class or a class with the same name higher in the hierarchy is returned.
* Need to provide a CallFrame for the visibility context.
A couple specialized constructors were added that minimize the number of initializations that are then assigned to. This ensures that the Message instance is fully initialized before being used and avoids an extra call to Message::setup. Effective C++ suggests the compiler may be able to emit better code in this case. Overall, the code for the send_* instructions is significantly cleaner.