Hi Mats & others,
the idea is actually not mine; I copied it almost verbatim from ParcPlace Smalltalk (now Cincom VisualWorks). VW has the following combinations:

00 object pointer
01 character
10 forbidden
11 small integer

This has the big advantage that the tag bits have individual semantics: bit 0 is the "immediate" bit, and bit 1 is the "small integer" bit. So to check whether something is a SmallInt, you just have to check one bit. In a similar vein, to check whether an oop is a legal pointer into memory and can be dereferenced, you also have to check just one bit. Since both of these operations are fairly common in the VM, they should be as cheap as possible, and on most architectures multi-bit tests are a bit more expensive than single-bit tests.
In Squeak, there is the additional complication that the 10 tag bit combination is used by the GC machinery to detect object headers when walking through pointer objects. It works by scanning from the end of each pointer object and writes the 10 tag combination into the last header word first. When it finds that tag, it knows that it has reached the beginning of the object. The tag can then be reconstructed from other header information.
What my approach does differently from ParcPlace's is that 01 is just the tag for immediate non-integer objects. What you put into that 30-bit space is pretty much your business, but there are some constraints:

Since I'm currently focusing on getting SCAN into gear, I would like if somebody else could take over work on the 2-bit front. The old code is there to pilfer, and I would certainly engage in discussion about what should be implemented and what not. Specifically the networking aspects of Squeak need to be considered, which is radically different from the situation when I first implemented the stuff. Perhaps the 3D graphics guys should have a word, too.

Cheers,
Hans-Martin