Newsgroups: comp.lang.lisp,comp.lang.dylan
Path: cantaloupe.srv.cs.cmu.edu!rochester!cornellcs!newsstand.cit.cornell.edu!portc01.blue.aol.com!portc02.blue.aol.com!howland.erols.net!netcom.com!vrotney
From: vrotney@netcom.com (William Paul Vrotney)
Subject: Re: Inner Classes in Java
In-Reply-To: "Chris Page"'s message of 15 Nov 96 01:33:56 -0800
Message-ID: <vrotneyE14A76.EEx@netcom.com>
Organization: NETCOM On-line Communication Services (408 261-4700 guest)
References: <vrotneyE0wBzz.D5A@netcom.com> <AEB1790A-ACB8A@205.149.164.180>
Date: Tue, 19 Nov 1996 12:18:42 GMT
Lines: 229
Sender: vrotney@netcom7.netcom.com
Xref: glinda.oz.cs.cmu.edu comp.lang.lisp:23801 comp.lang.dylan:7580


In article <AEB1790A-ACB8A@205.149.164.180> "Chris Page" <page@best.com> writes:

> 
> William Paul Vrotney <vrotney@netcom.com> wrote:
> > In article <87hgn1o13r.fsf@lutefisk.jetcafe.org> jim@lutefisk.jetcafe.org
> > (James Stephen Larson) writes:
> > In article <vrotneyE0Hr4t.LM4@netcom.com> vrotney@netcom.com (William
> Paul
> > Vrotney) writes:
> [...]
> > 
> > What makes you think that a Lisp interpreter machine has to be a special
> > purpose machine?  Why is an Intel 486 interpreter any more general than a
> > Lisp interpreter?  You can say that the Lisp interpreter machine is
> > "higher level", but that should make the hardware faster.
> [...]
> > In some sense a Lisp interpreter machine is *more* general than a 486
> > interpreter machine.
> 
> I can see your point, and it reminds me of a comment a friend made about
> how these architectures are, in a sense, C-machines. But I'm only familiar
> with 680x0, PowerPC, and 80x86 hardware. I'd like to see an example or two
> of the higher-level features of your proposed Lisp-machine that could be
> executed more efficiently than, say, an equivalent series of PowerPC
> instructions. 

Fair enough.  But first I have to say that my proposal stressed the idea of
eliminating the need to compile (at least first for Lisp like languages).
Let's say that we could build a machine that executes Lisp like languages
with no compilation needed and that it could run as fast as, but maybe not
faster than a powerPC.  Would we have achieved something by any metric that
is worth spending any money on?  Also, I am not qualified to comment
authoritatively on such a machine. Someone like Steele could certainly
comment more substantially on such machine architectures.  But I will try
some ideas below, just don't expect too much.  In what I show below it is
assumed that CDR coding would be used on such a machine.  CDR coding is a 2
bit or small bit field in a cell that allows list expressions to be stored
efficiently as arrays.  It is very similar to the extension bits used in
conventional processor instructions.

First some background.  Note that the system would still have to do in
effect a "read" and macro expansions.  The macro expansion idea is
fundamentally important.  To a Common Lisp interpreter there are basically
only two kinds of instruction control schemas if you will.  One is function
expression evaluation, called "apply" in Common Lisp and the other is macro
expansion.  An implementation is allowed to implement any macro expansion as
a special form.  A special form is like a hard wired macro after it has been
expanded and optimized.  In Common Lisp there are a few "macros" that must
be implemented as special forms.  They are not called macros since some
special forms need to exist primitively.  Some of these that have
conventional processor counterparts are

        special form                    Conventional CPU
        ------------------------------------------------        
        go                              unconditional branch instructions
        if                              branch on condition instructions
        return-from                     Return from jump to subroutine
        setq                            load and store registers

An example of a macro that is not required to be a special form is the
"cond" macro because it can be expanded into a series of "if" special forms.

And then there are some that do not have conventional processor counterparts
but are generally important such as
        
        special form                    Meaning
        ------------------------------------------------        
        let                             bind some variables and execute
        lambda                          similar to let but can be "applied"

There are a few other special forms that have special importance, such as
handling conditions by unwinding stack frames, but not important for a
surface general discussion.

The "lambda" in Common Lisp is not specified as a special form but only as a
type of expression since lambdas are translated away by the compiler.
However in the Read Lisp machine a lambda would be considered more like a
macro or special form since it would not need to be compiled.  The lambda in
Common Lisp describes all of the semantics of functions.  Some conventional
processors have special instructions for calling functions and some have
special instructions to support when the function is called such as saving
and restoring some registers specified by a set of bits.  The lambda would
come closet to those kinds of instructions but with many other important
high level abstractions.  Also the lambda itself expresses the very notion of
computation in its simplest form in a realistic way.  Unlike the simplistic
and impossible to implement (requires an infinite tape) Turing machine the
lambda is quite attractive as a possible hardware implementation idea.

Lambda and "let" are both very important and similar in that implicit in
what the interpreter does with them involves the binding of variables to
values.  The closest thing to this in a conventional processor is loading
registers and stack offsets with values and then having a block of code
refer to those as variables.  This is one of the difficult tasks that is
left to the compiler to figure how.  That is, how to optimize, since the
conventional processor is not designed to do this implicitly.  A large
number of instructions have to be "compiled in" to the machine's memory to
make this happen successfully.  And even then there is no guarantee that the
instructions to do this will not break with an exception.  We just have to
have faith that the compiler writer and compiler user (programmer) are both
diligent.

The binding of variables could be a huge high level savings in execution
speed of the Read Lisp machine.  Especially if on chip caches could be used
in some clever way in conjunction with some design for a hardware binding
mechanism.  The safety of the Read Lisp machine would also be an improvement
because the reliance on the compiler and programmer to arrange all of the
instructions to do all this on the conventional processor would be
eliminated.

However, one of the biggest design tasks of a Read Lisp machine would be in
choosing how to do variable binding.  There have been some attempts at doing
this.  The problem on one hand is that there are so many choices.  Should
the variables be bound using a "deep" or "shallow" binding strategy?  Should
variables have dynamic and local extent?  How would function closures, a
special kind of binding come into the picture?  How could passing of
environments and continuations help in the mix?  For this surface level
discussion it is not necessary to understand these terms, only that they
present a number of choices for a hardware implementation.  On the other
hand, all of these choices offer more ways that they could be combined to
provide a more efficient hardware implementation.  That is to say that our
choices are not limited.

One big challenge of such a Read Lisp machine would be the efficient
representation and execution of symbolic functions and variable binding and
assignment.  For example if we had three sequential cells in memory

        foo
        arg1
        arg2

and this was to be interpreted as the function call

        (foo arg1 arg2)

the cell "foo" would be a pointer to some kind of object.  Ideally it would
be, as in Lisp software interpreters, a pointer to a symbol object and the
machine would extract the symbol's function object and apply to the
following arguments.  This process, ideally would be guided by the lambda
form mentioned earlier.  This also suggests some sort of hardware assist for
the lambda form itself.  If designed cleverly this could possibly be faster
that loading some registers, jumping to a subroutine and then saving some
registers.  However it seems that we could do better by having special
registers for such symbolic objects to accelerate these common operations
and avoid as much as possible any indirection usually suffered for software
interpreters on conventional processors.

This almost exact principle applies to symbolic variable assignment, for
example the three sequential cells in memory

        setq
        symbol
        value

This time instead of the register facilitating the function call it would
facilitate grabbing the symbol's value cell and set it to the value.  Binding
variables is similar

        let
        var1
        value1
        var2
        value2
        expression
 
In essence the the "var1" and "value1" are facilitated by the same kind of
register, however in the case of a variable binding a special kind of
assignment has to take place.  There could be a clever acceleration here
compared to conventional processors.  This is because the binding mechanism
is closely akin to the necessary extra instructions needed on the
conventional processor to save and restore registers.  That is, one has to
save a register before setting it to a new value then restore it to the old
value before when returning to the block of code from whence it sprang.  In
a similar way a symbol's value can change depending on it's environment.
Another difference is that on a conventional processor, and even a RISC,
there is a small number, or on a RISC, a finite number of such registers.
On the Read Lisp machine there would be an unlimited number of such bindable
symbols.

In recursion, the stack on a conventional processor grows quickly with new
bindings each time a function calls itself.  There may be possible ways to
improve on this with such a symbolic (not implying Symbolics like Machine).
like processor.  For example there could be a push stack list associated
with each symbol, eliminating extra instructions to mark stack frames on a
conventional processor and possibility eliminating the infamous stack
overflow problem.  Such "mini-stacks" could automatically be allocated to on
chip caches to accelerate the binding mechanism.  It is important to notice
that such binding environments of variables is typically per lambda or "let"
block a relatively small block of stuff that goes away after the exit of such
forms.

The design of such symbol registers on such a machine would be a critical
part of the aspect of the overall architecture.  In a Lisp world, symbols
are just objects like any other kind of object, however in the hardware they
would need to be treated as special objects.  All other objects could take
advantage of an on chip cache, where the interpretation of various
properties of the object would be done in parallel and quit fast.  One such
important property would be fast type checking and dispatching.  Another
important property would be the reference tree hardware to support garbage
collection.  Just in the area of hardware assisted garbage collection alone
would be a huge acceleration factor for such a machine.  Another advanced
opportunity for efficiency is in the area of parallel evaluation of
expression arguments.

A casual observer might say that this kind of Read Lisp machine is more
complicated than a CISC.  But once again, you could view this kind of
machine as not only more general but also as a reduced instruction set,
similar to a RISC.  For example a clever hardware implementation of a lambda
could offer reduction over the variety of instructions that would be needed
to implement it on a conventional processor and at the same time more bang
for the bits.


> instructions. In addition, I'd like to see how these might enhance
> execution of languages other than Lisp, or at least not slow them down or
> waste valuable logic gates.

If such computer architectures were to eventually flourish, for languages
that are non-Lisp like it is difficult to see how they would be enhanced,
perhaps they would, perhaps they wouldn't.  Perhaps such languages would
ultimately some day become obsolete, with the history that they were
designed too specifically for the old fashioned processor architecture.  One
might guess that processors 100 years from now would not have similar kinds
of architectures as those of today.


-- 

William P. Vrotney - vrotney@netcom.com
