5.23.3.11 objects.fs Implementation

An object is a piece of memory, like one of the data structures
described with struct...end-struct. It has a field
object-map that points to the method map for the object's
class.

The method map1 is an array that contains the
execution tokens (xts) of the methods for the object's class. Each
selector contains an offset into a method map.

selector is a defining word that uses
CREATE and DOES>. The body of the
selector contains the offset; the DOES> action for a
class selector is, basically:

( object addr ) @ over object-map @ + @ execute

Since object-map is the first field of the object, it
does not generate any code. As you can see, calling a selector has a
small, constant cost.

A class is basically a struct combined with a method
map. During the class definition the alignment and size of the class
are passed on the stack, just as with structs, so
field can also be used for defining class
fields. However, passing more items on the stack would be
inconvenient, so class builds a data structure in memory,
which is accessed through the variable
current-interface. After its definition is complete, the
class is represented on the stack by a pointer (e.g., as parameter for
a child class definition).

A new class starts off with the alignment and size of its parent,
and a copy of the parent's method map. Defining new fields extends the
size and alignment; likewise, defining new selectors extends the
method map. overrides just stores a new xt in the method
map at the offset given by the selector.

Class binding just gets the xt at the offset given by the selector
from the class's method map and compile,s (in the case of
[bind]) it.

I implemented this as a value. At the
start of an m:...;m method the old this is
stored to the return stack and restored at the end; and the object on
the TOS is stored TO this. This technique has one
disadvantage: If the user does not leave the method via
;m, but via throw or exit,
this is not restored (and exit may
crash). To deal with the throw problem, I have redefined
catch to save and restore this; the same
should be done with any word that can catch an exception. As for
exit, I simply forbid it (as a replacement, there is
exitm).

inst-var is just the same as field, with
a different DOES> action:

@ this +

Similar for inst-value.

Each class also has a word list that contains the words defined with
inst-var and inst-value, and its protected
words. It also has a pointer to its parent. class pushes
the word lists of the class and all its ancestors onto the search order stack,
and end-class drops them.

An interface is like a class without fields, parent and protected
words; i.e., it just has a method map. If a class implements an
interface, its method map contains a pointer to the method map of the
interface. The positive offsets in the map are reserved for class
methods, therefore interface map pointers have negative
offsets. Interfaces have offsets that are unique throughout the
system, unlike class selectors, whose offsets are only unique for the
classes where the selector is available (invokable).

This structure means that interface selectors have to perform one
indirection more than class selectors to find their method. Their body
contains the interface map pointer offset in the class method map, and
the method offset in the interface method map. The
does> action for an interface selector is, basically: