[self-interest] bytecodes

Marko Mikulicic marko at seul.org
Wed Nov 1 00:15:30 UTC 2000


Jecel Assumpcao Jr wrote:

> On Tue, 31 Oct 2000, Marko Mikulicic wrote:
> > Jecel Assumpcao Jr wrote:
>           someMethod = ( | tmp <- 9. r <- 7 |
>                  [ r < 10 ] whileTrue: [ | a <- 3 |
>                          r: r + a.
>                          r > tmp ifTrue: [ | z <- 0 | tmp: a + z ].
>                  ]
>           )
>
> This isn't supposed to make any sense at all. But if we look at the
> bytecodes inside the block used in 'ifTrue:'
>
>           81  = 0x51   readLocal 1
>          113 = 0x71   lexLevel 1
>           80  = 0x50   readLocal 0
>           32  = 0x20   send 0 "+"
>          114 = 0x72   lexLevel 2
>           98  = 0x62   writeLocal
>
> where lexical level 0, slot 1 is 'z', level 1 slot 0 is 'a' and level 2
> slot 2 is 'tmp'.

ah. I understand. This is only to allow fast indexing through local slots, without
literals.
But does it depend too much on the implementation ?
In some paper I have readed that the lowest level at wich Self code can access is
bytecodes and
in some other paper that the system tries hard to mantain the illusion that what
is going on is what the user expects.
For example, dynamic deoptimization and debugging. The original bytecode was quite
abstract and looked good
also when one thought of a block as a real object ... the bytecodes was so
abstract that they didn't depend on the lexical context
of the block. With this new bytecode set the illusion is broken, one knows that
the way that the system access the slots of higher lexical level
does not depend on hidden parent slot in the bock method pointing on the method
activation object (very selfish way of thinking, wich I love,
and I try to follow in the implementation unless impossible).
 This is not a big problem, but, you know, I'm very sensitive to this kind of
things :-)
This seems to me a step back into smalltalksih bytecodes and separating messages
from local variable access.
 Maybe I'm wrong but I see the bytecodes as part of the language, and unless
really necessary, avoid changing them.
I think that maybe for the interpreter there could be two levels of bytecode, one
created by the parser (the standard set) and
one deeper, closer to the interpreter (just in time interpreting). Of course there
is a waste of space (like for machine code) but at least
I don't break compatibility with older snapshots or Self programs wich accessed
bytecodes (emulators,...) only because I want to make my VM
portable.
 What do you think ?

>
> Exactly as you suggested - one for each "." separating expressions in a
> method. Though the methods are small, the lack of "pops" would cause an
> interpreter to leave garbage on the stack (tinySelf 1 does that, for
> example). Since you throw away a method's stack when it returns, it
> doesn't seem to matter. But if you write an interpreter like the
> original Digitalk Smalltalk/V that uses the hardware stack, this could
> become a problem.
>
> Note that a compiler has to do dataflow analysis on the method and can
> find out for itself which values are unused  even without "pop"
> bytecodes, which is why Self didn't use to have them.

My compiler simply leaves garbage on the stack until the end of the method where
the stack is reset to the previos frame before returning. Living without the frame
pointer
would be hard (activation access, debugging, GC) so there is no additional
overhead.
Why should the compiler try to analyze the dataflow (quite expensive) only to save
a couple of
words on the stack ?

>
>
> > Is the Java in Self emulator available to the public ?
> > I have readed something about. Is it at the base of the HotSpot java VM ?
>
> See http://www.sun.com/research/kanban/

Cannot find any links regarding Pep.

>
> My impression is that Pep was just a proof of concept. HotSpot was
> derived from Animorphic's Java implementation. But others in this list
> know much more about it than I do.

Can someone point me to an old thread where this theme was discussed, please ?
I have a feeling I saw this already :-)

> > > For those who missed it, I had made a proposal which used only 4
> > > bytecodes (0 = push literal, 1 = send, 2 = selfSend, 3 =
> > > nonLocalReturn) and used primitives for resends.
> >
> > Power of simplicity :-)
> > I think I missed it. Some considerations:
> > [...]
> > I think bytecodes must encode in the most efficient way the behaviour of a
> > method; they must not follow the phylosophy of self step by step.
>
> Sorry - I shouldn't have called them "bytecodes". In my scheme there is
> only the literal vector, and all multiples of 16 (starting with 0) are
> a smallInt containing 15 2 bit opcodes. The literals are used in
> sequence so there is no need of an index field or an index extension
> instruction. The "push self" bytecode is replaced with an
> "implicitSelfSend 'self'" instruction. This works since all method
> objects have a ':self*' slot. The literal vector for the value method
> in the block in my example would look like:
>
>       0: 10 10 01 10 00 00 00 00 00 00 00 00 00 00 00 00
>       1: 'z'
>       2: 'a'
>       3: '+'
>       4: 'tmp:'
>
> Though this encoding can have repeated literals, it actually uses up
> less memory than the normal one.

Very good idea.
Hope you didn't patent it :-)
Can you tell me how less memory uses.

the example above would be:
(0 = push literal, 1 = send, 2 = selfSend, 3 =

0: selfSend, 0
1: selfSend, 1
2: push, 2
3: selfSend, 3
----------
1*3 = 3 bytes

1: 'z'
2: 'a'
3: '+'
4: 'tmp:'
------
4*4 = 16 bytes

total: 19 bytes    versus yours 5*4 = 20 bytes   => you loose 1 byte :-)

I imagine that for a bit longer methods there is a gain of 1 byte (at least for 16
codes).
But every duplicate eats 4 bytes!

I'm very interested to see what the real-world says.
Have you implemented this on something that can read the self4 world ?

>
>
> > I'm interested to see how many "index" bytecodes are in the 4.1.2 world as
> > opposed as in the 4.0 world,
> > and also the mean length of methods in the two systems. Can anyone try to get
> > this infos ?
>
> Self 4.0:
>
>    mean length = 184835 / 26369 = 7.00956 bytes
>    mean literals = 141237 / 26369 = 5.35618
>    index bytecodes = 3233
>
> Self 4.1.2
>
>    mean length = 356743 / 37376 = 9.54471 bytes
>    mean literals = 152172 / 37376 = 4.07138
>    index bytecodes = 15386
>
> So while there are more bytecodes (5 times the number of index
> bytecodes), there are less literals (the readLocal and writeLocal
> bytecodes don't used them, while the implicitSelfSelf does) for a net
> saving of 3.66 bytes per method.

Very interesting! Can you please also tell me the mean size of the literals (I
suppose the "mean literals" above
is the number of literals per method) to estimate the percentual saving of 3.66
bytes per method ?

>
>
> > What are the advantages of the 4.1.2 bytecodes. Is it because of the
> > interpreter ?
>
> Exactly.
>
> > I have implemented the VM using 8 bytecodes. Do you think it could be helpful
> > use the 4.1.2 sheme ?
>
> Only if you have an interpreter or if you want to be able to read in
> snapshots created by Self4.1.2.

I thought to stay more or less compatible but I think I won't follow that.
Maybe it won't be bad if we could share the images between OpenSelf and Self/R.
What have you implemented until now, Jacel ?

Marko




More information about the Self-interest mailing list