[Date Prev][Date Next][Thread Prev][Thread Next][Author Index][Date Index][Thread Index]

Strong pointers and forward declarations



Highlights:

- A brief overview of the declaration hooks being introduced for the garbage
  collector.
- There is a problem with forward declaration of classes that must be pointed
  to strongly for garbage collection.
- There is a solution to the problem that requires lots of extra verbiage in
  the code, but is at least enforced at compile time.  Additionally, the ugly
  part can be automatically generated in code translated from Smalltalk.
- A Turing complete preprocessor would be nice, but would open a can full of
  support worms.

Lowdarks:

  To support garbage collection, two new kinds of "pointers" have been
introduced, and the old kind has been renamed.  The new pointers are strong
pointer to type, or SPTR(type), and checked pointer to type, or CHKPTR(type).
To avoid having an unmarked case, conventional pointers have been relabeled
as wimpy pointer to type, or WPTR(type).
  SPTRs and CHKPTRs are Var-like classes that overload all of the operators
that one uses with pointers, such as *, ->, ==, and =, and are used to point
at entities that must survive garbage collection.  CHKPTRs occur as instance
variables in classes in order to string together data structures that are
walked by the collector.  SPTRs are virtually identical to CHKPTRs, but are
used to point to the roots of things.  They occur as automatic variables,
arguments, fluid variables, and are implemented so that temporaries are also
strong.  The reason these are two different types is that CHKPTRs just sit
there, whereas SPTRs must be strung together so that all the roots can be
seen, and must be unstrung when their scope is left--like Bombs.  In fact,
SPTR(type) is implemented as a subclass of BombSuperclass.  CHKPTR(type) is
a subclass of Var.  WPTR(type) is presently nothing more than syntactic
vinegar for type*, but there are schemes afoot to use it for later debugging
if needed.
  The classes for SPTR(type) and CHKPTR(type) are declared by the macro
CHECKED_CLASS(type).  As an example of their use consider the following class
declaration.  Some new things are shown, as well as part of the current
solution to the forward declaration problem of the next section.

#ifndef CHECKED_Bar
CHECKED_CLASS(Bar);
#define CHECKED_Bar
#endif /* CHECKED_Bar */
CLASS(Bar,Foo) {
  PUBLIC:
    SPTR(Object) method (SPTR(UnaryOp) op, SPTR(Object) arg,
                         WPTR(Category) cat) {
	if (arg->isKindOf(cat)) {
	  return op->of(arg);
        } else {
          return instance1;
        }
    }
    ...
  PRIVATE:			/* declares instance marking method */
    CPTR(Object) instance1;	/* examined at garbage marking */
    WPTR(Object) instance2;	/* not examined */
};

The method declared here declares both op and arg to be roots for the
garbage collector.  The result of also declared as a strong pointer so that any
compiler produced temporaries that may contain it will also be seen as roots.
The argument cat is declared as wimpy since it is of no interest to the
garbage collector (category objects being static).

  The problem arises when one wishes a forward declaration of a type that has
SPTRs and CHKPTRs to it.  It is not sufficient to have a FORWARD_CLASS(type)
macro simply expand to
	class type;
	class SPTR(type);
	class CHKPTR(type);
since the last two declarations do not inform the compiler of the pointerish
nature of SPTR and CHKPTR.  The other way to try to do this (the one I first
tried) is to have FORWARD_CLASS expand to
	class type;
	...real declaration of SPTR(type)...
	...real declaration of CHKPTR(type)...
The problem with this is that it is often the case that many FORWARD_CLASS
macros to the same class will be encountered while compiling a given file.
It also happens that while the ?.hxx file may have a forward declaration,
the ?.cxx file might include the hxx file where class type, and therefore
SPTR(type) and CHKPTR(type), are defined.  These result in "class defined twice"
errors.

  After these two tries, I got a headache and went to lunch and talked with
Hugh (Hoover) about the problem.  Lots of moaning and groaning resulted, as
well as a (sort of) solution.  A phone conversation with MarkM resulted in
more groaning and some refinements.

  The #ifndef in the above example is the central feature of the "solution" to
the problem.  Basically I define a macro CHECKED_CLASS(type) which expands
exactly as the second example above, but is ALWAYS presented to the compiler
as
	#ifndef CHECKED_type
	CHECKED_CLASS(type);
	#define CHECKED_type
	#endif /* CHECKED_type */
This macro is used both for forward declarations and in the neighborhood of
the actual declaration for class type.  The macro DEFINE_CHECKED_CLASS is then
defined to perform the job of the original DEFINE_CLASS macro, as well as
defining the methods for SPTR(type) and CHKPTR(type).  This does the required
job.  That it will also cruft up the code from a read/write-ability point of
view should be apparent.  Its two saving graces are that the compiler will
produce errors if this is not done correctly, rather than obscure runtime
problems, and that the Smalltalk translator can produce this stuff automatically.

  Since I need a solution to this NOW, I am going ahead with this approach.
I implore somebody to come up with a better way.  The most desirable way would
be to have a smarter preprocessor that could include and then evaluate #ifdefs
and #defines within macros.  MarkM tells me that at Datapoint there was such
an animal based on the macro processor from the book "Software Tools."  I'm
interested to hear if anybody has such a preprocessor "on the shelf" somewhere.
It should be noted though that even if we can get one, that it would be yet
another strand in the X++ pile of spaghetti that we would have to support, and
therefore possibly undesirable in any case.

Ugh.

	- e -