I successfully ported the NanoVM (www.harbaum.org/till/nanovm/) to the
cc65 toolchain (www.cc65.org).
It's a very minimalistic Java implementation written in portable C.
The binary built with cc65 is only 16kB.
The NanoVM source is available via anonymous CVS access at
SourceForge.net (sourceforge.net/projects/nanovm/).
To allow you easy access I created a zip file
(www.jantzer-schmidt.de/nanovm-cc65.zip) containing:
1. The tool necessary to convert .class files into an .nvm file to be
loaded by the NanoVM in case you want to create your own Java
programs.
2. An Apple2 .dsk image file containing the NanoVM binary together
with some samples. Type 'EXEC <TXT File> to run one of the sample Java
programs.
3. A C64 .d64 image file containing the NanoVM binary together with
some samples. Type 'RUN:REM <NVM File> to run one of the sample Java
programs.
The source of the sample Java programs can be viewed via CVS
repository browsing
(nanovm.cvs.sourceforge.net/nanovm/nanovm/java/examples/).
Best, Oliver
Wow! Great work Oliver. I'm going to have a play with this
tonight. :-)
cheers,
-p
But I have to ask ... any idea as to when Contiki 2.x for the C64 will
be ready and workable ? :-)
Mark
What do you plan on doing with it?
Rich
> > It's a very minimalistic Java implementation written in portable C.
> > The binary built with cc65 is only 16kB.
>
>
> What do you plan on doing with it?
bets on something Contiki'ish.
--- Synchronet 3.14a-Win32 NewsLink 1.85
A2Central.com - Your total source for Apple II computing.
> > It's a very minimalistic Java implementation written in portable C.
>
> What do you plan on doing with it?
Tsk, you've totally missed the point...
Ok, I missed it too, can you please show us what is the point, apart that
"it can be done"?
quicksort.nvm seems slow as if made in basic. I don't find it useful in any
manner.
--
-=[]=--- iAN CooG/HokutoForce ---=[]=-
> >>> It's a very minimalistic Java implementation written in portable C.
>
> >> What do you plan on doing with it?
>
> > Tsk, you've totally missed the point...
>
> Ok, I missed it too, can you please show us what is the point, apart that
> "it can be done"?
That WAS my point :) Putting a JVM on a C64 is one of those things
that one does either as a computer science term project, or to show
that it can be done. The latter seems to apply in this case.
> Ok, I missed it too, can you please show us what is the point, apart that
> "it can be done"?
Why do we do *anything* on the old 8-bits? Anything we do as part of this
hobby (apart from preservation) could be done much, much easier on modern
PCs.
I think the Japanese art of Chindogo captures it nicely:
"Chindogu is the Japanese art of inventing ingenious everyday gadgets that,
on the face of it, seem like an ideal solution to a particular problem.
However, Chindogu has a distinctive feature: anyone actually attempting to
use one of these inventions, would find that it causes so many new problems,
or such significant social embarrassment, that effectively it has no utility
whatsoever. Thus, Chindogu are sometimes described as 'unuseless' - that is,
they cannot be regarded as 'useless' in an absolute sense, since they do
actually solve a problem; however, in practical terms, they cannot
positively be called 'useful'."
http://en.wikipedia.org/wiki/Chindogu
-Leif
--
Leif Bloomquist
leif(at)schemafactor(dot)com
http://home.ica.net/~leifb/
"Time flies like an arrow, just not towards me."
Fun, especially, and I think Oliver had lots making this porting. The part
"It can be done and I can" is a common thought for coders.
I was only asking what was the point of a NanoVM on the C64, like the one
who asked "What do you plan on doing with it?
". I was just curious about what's the future of this project and his
possibile implementations.
If it will be included in some project as Contiki 1.3 (if someone will fork
1.2 to fix/extend it) it will be also useful in some way.
Else it will go directly to the "useless tools" compo of this year. :D
--
-=[]=--- iAN CooG/HokutoForce ---=[]=-
RAM = Rarely Adequate Memory
Interesting parallel to Douglas Adams' riff on the "Serius Computer
Companies" products in Hitchhiker's Guide to the Galaxy:
<sloppy paraphrase from memory>
The Serius Computer Company's products are so difficult to use and so
filled with superficial bugs that no one ever finds their underlying
major design flaws that prevent them from working at all.
</sloppy paraphrase from memory>
-michael
NadaNet file server for Apple II computers!
Home page: http://members.aol.com/MJMahon/
"The wastebasket is our most important design
tool--and it's seriously underused."
To give me horrible nightmares?
Very good work though. I never would have expected anything Java within a
stone throw (or serial cable) of an 8-bitter.
--
-----> http://members.dodo.com.au/~izabellion1/tristan/index.html <-----
===== It's not pretty, it's not great, but it is mine. =====
Very nice! I translated some of the NanoVM docs to English in case
anyone is interested:
http://www.EricEngler.com/NanoVM.aspx
NanoVM was originally written to target the small Asuro robot where it
lives within a small AVR ATMega8 microcontroller. It is mostly written
in portable C, allowing people to port it to other platforms.
The Apple 2 is a giant platform for this small VM, so it should be
possible to write some cool programs with it.
And the cc65 small C compiler is also very cool, so the marriage of
these 2 platforms will give us a lot of new software to play with.
Eric
>Hi,
>
>I successfully ported the NanoVM (www.harbaum.org/till/nanovm/) to the
>cc65 toolchain (www.cc65.org).
That is very very cool. Time to inspect...
> And the cc65 small C compiler is also very cool, so the marriage of
> these 2 platforms will give us a lot of new software to play with.
Knowing nothing about C or Java, I boldly ask:
What benefits does this bring that might spur on a rash of new software
development? I can't imagine it being easier than AppleSoft or more
efficient than Assembly... so are we talking improved functionality, or is
it just that more people are familiar with C and Java than the older
languages?
-s
_____
|[LD8]! 8-BIT SOUND & FURY : APPLE ][ AUDIO & MUSIC RESOURCES
| o. | +--------- http://8bitsoundandfury.ld8.org ---------+
!__!__! OLD APPLE WEB SERVER LIST http://www.ld8.org/servers
> > Tsk, you've totally missed the point...
>
> To give me horrible nightmares?
>
> Very good work though. I never would have expected anything Java within a
> stone throw (or serial cable) of an 8-bitter.
Well really, the JVM isn't that far removed from the UCSD p-System it
was (partly) inspired by. The degree of inefficiency implied by the
degree of indirection inherent in object oriented programs probably
implies that the paradigm has little practical use on such a small
machine, whether bytecode interpreted or not.
If it serves to break the "Java/.NET/VM" languages are inefficient
meme, then this project has a practical use that I applaud.
Matt
> Well really, the JVM isn't that far removed from the UCSD p-System it
> was (partly) inspired by.
That's true. The main differences are automatic garbage collection and
OOP support. Otherwise the basic concept of the JVM builds directly on
the p-System ideas.
> The degree of inefficiency implied by the
> degree of indirection inherent in object oriented programs probably
> implies that the paradigm has little practical use on such a small
> machine, whether bytecode interpreted or not.
It's certainly going to be slower than using cc65 directly, but this
is due mostly to the inefficieny of the VM layer and not really
because of the OOP. Static functions in Java don't require object
instances, so you don't always have to live with indirection of each
object. Static member invocation is about 10 times faster than
instance invocation in general, but once you factor in the time it
takes to do the processing in the function it can swamp the overall
benchmark numbers. We rarely call empty functions.
In all honesty, this is most practical in the sense that it's cool!
This is not going to win any converts who already use native code
compilers or assemblers. But it's possible that it might compete in
benchmarks with Applesoft. I would not try to "sell it" based on that,
of course. And I wouldn't bet the farm that it's going to be faster
than Applesoft.
Something we haven't mentioned yet is that the real power in Java is
not in the language itself, or even the JVM. It's the wide-spanning
class libraries that make Java kick butt because you can leverage
thousands of lines of code written and debugged by other people. And
NanoVM does NOT include those huge class libraries. We clearly won't
be able to have a full Java environment for the Apple 2.
The mere fact that you can run simple Java programs on an Apple is
exciting. And the Apple can even serve as a devlopment platform for
Java programs that run on the small microcontrollers.
Eric
> The mere fact that you can run simple Java programs on an Apple is
> exciting. And the Apple can even serve as a devlopment platform for
> Java programs that run on the small microcontrollers.
I presume you mean the Apple II could serve the role of a
"development board" for running small programs, not hosting
a development environment--like a Java compiler.
Of course, most such programs would use application-specific
I/O and human interfaces, so the Apple II may not be a very
useful match.
However, the Apple II p-System is very heavily optimized for the
"under 64KB" environment. In particular, the bytecodes are very
tightly encoded to improve code compaction.
The encoding of Java bytecodes is much looser, and so should be
much less space efficient for typical under-64KB programs.
Applesoft, often maligned for its incomplete interpretive coding,
is actually relatively compact in its code representation--though
it pays for it in rutime inefficiencies. (I occasionally wonder
how much faster it would be if variable and statement addresses
were "backpatched" into the code during execution, eliminating the
painful linear searches to resolve them...)
> If it serves to break the "Java/.NET/VM" languages are inefficient
> meme, then this project has a practical use that I applaud.
Of course, interpretation is only inefficient when used in a way
that results in slower overall execution than not using it. If an
application can run slowly in an interpretive system, but cannot
run at all in a non-interpretive environment, then interpretation
is much faster. ;-)
In any memory-constrained system, there is a good chance that
interpretation, full or partial, can be used to increase code
compaction to a significant degree. In many cases, this might
make the difference between practicality and impracticality.
In fact, interpretation is just a particular way of factoring out
chunks of code that are frequently used. Other related methods
are threaded code and procedure calls.
Both bytecodes seem to have a very similar stack based architecture. The
p-system was designed to run in 64k, so many concessions had to be made
to create a full IDE written in itself as well as I/O. Segment swapping
was essential to getting just about anything to run. Java never really
had that kind of constraint placed on it. Looking at the NanoVM
implementation and having looked at the code cc65 generates, I'm
actually amazed and impressed that it works so well. I bet a hand tuned
6502 JVM implementation would be close in performance to the 6502
p-machine. Compiler differences would be interesting. One would think
compiler technology had advanced in 20 years and the advantage a Java
compiler would have by running on *big iron* vs. a p-system based Pascal
compiler should give the edge to Java. An intriguing subject.
> Applesoft, often maligned for its incomplete interpretive coding,
> is actually relatively compact in its code representation--though
> it pays for it in rutime inefficiencies. (I occasionally wonder
> how much faster it would be if variable and statement addresses
> were "backpatched" into the code during execution, eliminating the
> painful linear searches to resolve them...)
I actually thought that was all the Applesoft compilers really did.
>
>> If it serves to break the "Java/.NET/VM" languages are inefficient
>> meme, then this project has a practical use that I applaud.
>
> Of course, interpretation is only inefficient when used in a way
> that results in slower overall execution than not using it. If an
> application can run slowly in an interpretive system, but cannot
> run at all in a non-interpretive environment, then interpretation
> is much faster. ;-)
>
> In any memory-constrained system, there is a good chance that
> interpretation, full or partial, can be used to increase code
> compaction to a significant degree. In many cases, this might
> make the difference between practicality and impracticality.
>
> In fact, interpretation is just a particular way of factoring out
> chunks of code that are frequently used. Other related methods
> are threaded code and procedure calls.
>
> -michael
>
> NadaNet file server for Apple II computers!
> Home page: http://members.aol.com/MJMahon/
>
> "The wastebasket is our most important design
> tool--and it's seriously underused."
I guess I have never been a fan of bytecoding. For the p-system, it was
a way to port to many different architectures without undo effort. For
Java, it was security. However, for a memory constrained environment,
it seems interpreting a tokenized language gives the most space saving
and flexibility. Having to compile to a bytecode ruins the
interactivity and some semantics and still leaves you having to
interpret the output, just at a lower level. If you're going to
compile, then go all the way. If you're going to interpret, keep it
close to the source. JIT compilation would have a lot more to work with
using a tokenized representation vs somebody's notion of what a CPU
should look like.
Well, that's what *I* would do if anyone asked.
Dave...
The interpretive stack machine is a common idea, but the encoding
of operators/operands is much different. P-code is very tight because
of the constraints imposed, while Java never had those constraints, and
therefore has larger limits, and thus less dense coding.
> Looking at the NanoVM
> implementation and having looked at the code cc65 generates, I'm
> actually amazed and impressed that it works so well. I bet a hand tuned
> 6502 JVM implementation would be close in performance to the 6502
> p-machine. Compiler differences would be interesting. One would think
> compiler technology had advanced in 20 years and the advantage a Java
> compiler would have by running on *big iron* vs. a p-system based Pascal
> compiler should give the edge to Java. An intriguing subject.
I would be very surprised to see *any* high-level implementation of
an interpreter get within a factor of two of the speed of a tuned
assembly version--particularly if the interpretive operations are
low semantic level, like "add 16-bit integer".
>> Applesoft, often maligned for its incomplete interpretive coding,
>> is actually relatively compact in its code representation--though
>> it pays for it in rutime inefficiencies. (I occasionally wonder
>> how much faster it would be if variable and statement addresses
>> were "backpatched" into the code during execution, eliminating the
>> painful linear searches to resolve them...)
>
>
> I actually thought that was all the Applesoft compilers really did.
Pretty close--but most of them compile into strings of procedure
calls. It would be possible to keep all the interactive editing,
etc., of Applesoft but accelerate it with on-the-fly speedups
as statements were executed the first (or second) time.
>>> If it serves to break the "Java/.NET/VM" languages are inefficient
>>> meme, then this project has a practical use that I applaud.
>>
>>
>> Of course, interpretation is only inefficient when used in a way
>> that results in slower overall execution than not using it. If an
>> application can run slowly in an interpretive system, but cannot
>> run at all in a non-interpretive environment, then interpretation
>> is much faster. ;-)
>>
>> In any memory-constrained system, there is a good chance that
>> interpretation, full or partial, can be used to increase code
>> compaction to a significant degree. In many cases, this might
>> make the difference between practicality and impracticality.
>>
>> In fact, interpretation is just a particular way of factoring out
>> chunks of code that are frequently used. Other related methods
>> are threaded code and procedure calls.
>
>
> I guess I have never been a fan of bytecoding. For the p-system, it was
> a way to port to many different architectures without undo effort. For
> Java, it was security. However, for a memory constrained environment,
> it seems interpreting a tokenized language gives the most space saving
> and flexibility. Having to compile to a bytecode ruins the
> interactivity and some semantics and still leaves you having to
> interpret the output, just at a lower level. If you're going to
> compile, then go all the way. If you're going to interpret, keep it
> close to the source. JIT compilation would have a lot more to work with
> using a tokenized representation vs somebody's notion of what a CPU
> should look like.
>
> Well, that's what *I* would do if anyone asked.
The problem with compiling "all the way" is that it takes a lot more
space than a compact bytecode. Most of the semantics involve at least
16-bit arithmetic, so the usual tradeoff is to use JSRs to "execute
routines". At that point, Just using threaded code would eliminate
all the JSR opcodes, saving about 30% (of course, at the cost of a
couple of instructions per "operation".
Interpretation really pays off in two cases: 1) when it saves space
on code seldom (or never) executed--like error recovery code--and 2)
when the semantic level of the operations is relatively high, so that
the average interpretive operation is many machine instructions--
floating point and graphics operations come to mind.
In the first case, compressing necessary (but performance-irrelevant
code) allows more functions and more efficient implementation of the
functions that matter, and in the second case, the interpretive overhead
becomes a very small fraction of the total execution time.
The most efficient compilers I have ever encountered, in terms of space-
speed tradeoff, used a fluid mix of interpretation, threaded code, and
in-line code during compilation. (They compiled to full in-line code.)
Exactly which method to use for performing each function was determined
by careful profiling of the compiler. Saving space in infrequently used
parts of the code allowed more space for performance-critical parts to
be coded in-line.
>> Applesoft, often maligned for its incomplete interpretive coding,
>> is actually relatively compact in its code representation--though
>> it pays for it in rutime inefficiencies. (I occasionally wonder
>> how much faster it would be if variable and statement addresses
>> were "backpatched" into the code during execution, eliminating the
>> painful linear searches to resolve them...)
>
> I actually thought that was all the Applesoft compilers really did.
I think pre-parsing literal numbers was one more thing they did, right?
Even Apple's own manual warned that number parsing was particularly slow.
--
Linards Ticmanis
I'll try it on my //e, my //gs and my emulator that I wrote (Appleuni),
when I get the chance/if I remember to do so this week... and I'll let
you know what explodes. XD
>> Looking at the NanoVM
>> implementation and having looked at the code cc65 generates, I'm
>> actually amazed and impressed that it works so well. I bet a hand tuned
>> 6502 JVM implementation would be close in performance to the 6502
>> p-machine. Compiler differences would be interesting. One would think
>> compiler technology had advanced in 20 years and the advantage a Java
>> compiler would have by running on *big iron* vs. a p-system based Pascal
>> compiler should give the edge to Java. An intriguing subject.
>
>I would be very surprised to see *any* high-level implementation of
>an interpreter get within a factor of two of the speed of a tuned
>assembly version--particularly if the interpretive operations are
>low semantic level, like "add 16-bit integer".
I don't think that Java byte code is large or "loose", in fact in my
opinion the opposite is true.
Writing a Java interpreter in 6502 assembly would most probably bring
Java close to the p-machine.
>The problem with compiling "all the way" is that it takes a lot more
>space than a compact bytecode.
That's the key! At work I was several years dealing with analyzing and
building Java VMs. The very advanced technology currently is Sun's
HotSpot VM. It's a great example of not compiling all code but mixing
interpretation and JIT compiling. Most people don't know that the
HotSpot VM even 'decompiles' code, which means it throws away compiled
native code and instead uses the interpreter again !
The major two benefits of this approach are:
1. Even with todays large memory areas memory consumption is still a
very important aspect: Because of the hierarchical memory systems -
There a Level 1 cache, a Level 2 cache, a Level 3 cache, the main RAM,
the memory paged to disk. The speed difference between CPUs and main
RAM became larger and larger in the recent years. Today memory
bandwidth is the primary limitation factor. So interpretation of very
compact byte code can be in fact faster than executing large native
code. The threshold depends on the workingset size (i.e. small tight
loop vs. jumping back and forth in large program). So a reason for
decompilation here could be that the code isn't executed often enough
anymore and therefore get's replaced by more "hot" code in the
'compiled code cache'. That cache intentionally doesn't jus grow to
keep it in a certain Level x hardware cache.
2. JIT (aka 'dynamic') compiling allows for quite some optimizations
not possible with Ahead-Of-Time (aka 'static') compiling. I.e. because
it's the default in Java most methods are virtual. But depending on
the currently loaded classes method calls often can only target a
single class thus can be handled as non-virtual. These type of
analysis (and many more) are done my the HotSpot compiler. So a reason
for decompilation here could be that the compiled code got wrong in
the meanwhile due to i.e. additionally loaded classes. In this context
it is obligatory that the VM can decompile code of methods being
actually executed ! In the case of the HotSpot VM that's true as well
for compilation: Just think of the "main loop" of some program. At the
time it becomes clear that it is "hot" enough to be compiled it
doesn't make sense to wait for the next time it's not executed. This
type of compilation/decompilation of running methods is btw called
'on-stack-replacement'.
Best, Oliver
It's been years since I looked at Java bytecode, so I'll have to take
another look. I presume that this is a very stable definition, since
portability would demand it.
> Writing a Java interpreter in 6502 assembly would most probably bring
> Java close to the p-machine.
IIRC, the p-machine has single-byte operations that push common
constants and designate parameters, for example, without an additional
operand byte. These coding cases were chosen to minimize code size
in a way that few bytecodes attempt.
>>The problem with compiling "all the way" is that it takes a lot more
>>space than a compact bytecode.
>
>
> That's the key! At work I was several years dealing with analyzing and
> building Java VMs. The very advanced technology currently is Sun's
> HotSpot VM. It's a great example of not compiling all code but mixing
> interpretation and JIT compiling. Most people don't know that the
> HotSpot VM even 'decompiles' code, which means it throws away compiled
> native code and instead uses the interpreter again !
I presume that it doesn't really "decompile", but simply throws away
the compiled code and reverts to the still available bytecode
representation.
This is actually a quite venerable technique, known as "throwaway
compiling", and was originally part of a strategy in which compiled
code was kept in a size-limited buffer, and the least-recently-used
parts were simply thrown away when newer code needed to be generated.
So the compiled code was managed just like a page working set, or
a code cache. Some CISC chip microarchitectures have taken a similar
approach to translating their advertised "machine code" into their
native RISC-like instructions.
The original RISC principle was to do as much as possible once, at
compile time rather than repeatedly at execution time, and these
techniques are points on a continuum of approaches between "fully
static" translation and "fully dynamic" execution.
>> Writing a Java interpreter in 6502 assembly would most probably bring
>> Java close to the p-machine.
>
>IIRC, the p-machine has single-byte operations that push common
>constants and designate parameters, for example, without an additional
>operand byte. These coding cases were chosen to minimize code size
>in a way that few bytecodes attempt.
You're surely right that this is something not done with Java byte
code. But my statement above was targeted towards performance and not
code density.
>I presume that it doesn't really "decompile", but simply throws away
>the compiled code and reverts to the still available bytecode
>representation.
You're presumption is correct for sure.
>This is actually a quite venerable technique, known as "throwaway
>compiling", and was originally part of a strategy in which compiled
>code was kept in a size-limited buffer, and the least-recently-used
>parts were simply thrown away when newer code needed to be generated.
>
>So the compiled code was managed just like a page working set, or
>a code cache.
This seems to decribe the same approach I described - or do I miss the
point here ?
>Some CISC chip microarchitectures have taken a similar
>approach to translating their advertised "machine code" into their
>native RISC-like instructions.
>
>The original RISC principle was to do as much as possible once, at
>compile time rather than repeatedly at execution time, and these
>techniques are points on a continuum of approaches between "fully
>static" translation and "fully dynamic" execution.
Interesting aspect - at least to me - that this type of consideration
was/is applied to hardware designs as well - and especially that the
CISC vs. RISC discussion can be seen in this metrics.
Best, Oliver
And code density is the point I was addressing, contrasted with
the relatively "looser" Java bytecode.
>>I presume that it doesn't really "decompile", but simply throws away
>>the compiled code and reverts to the still available bytecode
>>representation.
>
>
> You're presumption is correct for sure.
>
>
>>This is actually a quite venerable technique, known as "throwaway
>>compiling", and was originally part of a strategy in which compiled
>>code was kept in a size-limited buffer, and the least-recently-used
>>parts were simply thrown away when newer code needed to be generated.
>>
>>So the compiled code was managed just like a page working set, or
>>a code cache.
>
>
> This seems to decribe the same approach I described - or do I miss the
> point here ?
I agree--and I was pointing out that the practice is over 30 years
old, dating back to the very beginnings of time-sharing and interactive
computing. Novelty is hard to come by in this field. ;-) Many recent
"discoveries" in computing are simply re-discoveries by folks who either
forgot about the past or never bothered to learn it.
>>Some CISC chip microarchitectures have taken a similar
>>approach to translating their advertised "machine code" into their
>>native RISC-like instructions.
>>
>>The original RISC principle was to do as much as possible once, at
>>compile time rather than repeatedly at execution time, and these
>>techniques are points on a continuum of approaches between "fully
>>static" translation and "fully dynamic" execution.
>
>
> Interesting aspect - at least to me - that this type of consideration
> was/is applied to hardware designs as well - and especially that the
> CISC vs. RISC discussion can be seen in this metrics.
Of course, this applies primarily to CISC processors, for which the
major complexity is in their firmware rather than the usually RISCy
underlying hardware. The x86 processors are a prime example.
The dynamic compilation approach that has the most practical promise
at the moment is dynamic optimization of running machine code, directed
by real-time profiling.
Since most programs now involve very high frequencies of module-
crossings, and most modules are independently compiled, it is only
at runtime that the actual content of many loops becomes evident,
and only then that calls can be in-lined and optimized.
Perhaps in the future we will see automatic parallelism "extractors"
that can begin to capitalize on the dozens of processors that will
soon be in mass-market chips. It seems pretty clear that we will
take much longer to get most programmers up to speed on efficient
parallel computing. ;-(
On 8/12/07 4:55 PM, in article Do-dnUOxXNje6SLb...@comcast.com,
"Michael J. Mahon" <mjm...@aol.com> wrote:
> Oliver Schmidt wrote:
...
>>
>>
>> This seems to decribe the same approach I described - or do I miss the
>> point here ?
>
> I agree--and I was pointing out that the practice is over 30 years
> old, dating back to the very beginnings of time-sharing and interactive
> computing. Novelty is hard to come by in this field. ;-) Many recent
> "discoveries" in computing are simply re-discoveries by folks who either
> forgot about the past or never bothered to learn it.
>
Agreed. I suggest anyone who thinks differently peruse
alt.folklore.computers for a while... It will make you realize that today's
innovations were yesterday's innovations...
Java bytecodes:
iconst_m1 02 → -1 loads the int value -1 onto the stack
iconst_0 03 → 0 loads the int value 0 onto the stack
iconst_1 04 → 1 loads the int value 1 onto the stack
iconst_2 05 → 2 loads the int value 2 onto the stack
iconst_3 06 → 3 loads the int value 3 onto the stack
iconst_4 07 → 4 loads the int value 4 onto the stack
iconst_5 08 → 5 loads the int value 5 onto the stack
from
http://en.wikipedia.org/wiki/Java_bytecode
and
http://java.sun.com/docs/books/jvms/second_edition/html/Mnemonics.doc.html
Here is the best p-code description I could find.
http://homepages.cwi.nl/~steven/pascal/book/10pcode.html
The JVM looks to have been created with a pretty reasonable attempt to
keep code density small. There are both 16 bit and 32 bit
address/offset version of the opcodes. Honestly, I never looked too
much into the JVM, but it looks like a viable platform for a 6502. The
bigger question remains as to the quality of the Java compilers, but I
think Oliver is on to something here.
>>> I presume that it doesn't really "decompile", but simply throws away
>>> the compiled code and reverts to the still available bytecode
>>> representation.
>>
>>
>> You're presumption is correct for sure.
>>
>>
>>> This is actually a quite venerable technique, known as "throwaway
>>> compiling", and was originally part of a strategy in which compiled
>>> code was kept in a size-limited buffer, and the least-recently-used
>>> parts were simply thrown away when newer code needed to be generated.
>>>
>>> So the compiled code was managed just like a page working set, or
>>> a code cache.
>>
>>
>> This seems to decribe the same approach I described - or do I miss the
>> point here ?
>
> I agree--and I was pointing out that the practice is over 30 years
> old, dating back to the very beginnings of time-sharing and interactive
> computing. Novelty is hard to come by in this field. ;-) Many recent
> "discoveries" in computing are simply re-discoveries by folks who either
> forgot about the past or never bothered to learn it.
>
One interesting application of compiling a opcode comes from the
original Windows EGA/VGA driver. A ROP3 code describes a bitwise
combination of source, pattern, and destination. All 256 combinations
would have overwhelmed the computers of the time, so a routine was
compiled on the fly to implement the ROP3. Nobody was sure why you
needed a ROP3, but in typical MS fashion, it was 1 better than the ROP2
used in other windowing systems of time. I think they're up to ROP11
now (with apologies to Spinal Tap).
Dave...
> Both bytecodes seem to have a very similar stack based architecture. The
> p-system was designed to run in 64k, so many concessions had to be made
> to create a full IDE written in itself as well as I/O. Segment swapping
> was essential to getting just about anything to run. Java never really
> had that kind of constraint placed on it. Looking at the NanoVM
> implementation and having looked at the code cc65 generates, I'm
> actually amazed and impressed that it works so well. I bet a hand tuned
> 6502 JVM implementation would be close in performance to the 6502
> p-machine. Compiler differences would be interesting. One would think
> compiler technology had advanced in 20 years and the advantage a Java
> compiler would have by running on *big iron* vs. a p-system based Pascal
> compiler should give the edge to Java. An intriguing subject.
They are certainly very similar, yeah, the JVM didn't have keeping the
codesize small as a design consideration.
> I guess I have never been a fan of bytecoding. For the p-system, it was
> a way to port to many different architectures without undo effort. For
> Java, it was security. However, for a memory constrained environment,
> it seems interpreting a tokenized language gives the most space saving
> and flexibility. Having to compile to a bytecode ruins the
> interactivity and some semantics and still leaves you having to
> interpret the output, just at a lower level. If you're going to
> compile, then go all the way. If you're going to interpret, keep it
> close to the source. JIT compilation would have a lot more to work with
> using a tokenized representation vs somebody's notion of what a CPU
> should look like.
>
> Well, that's what *I* would do if anyone asked.
I think in the case of Java et al, the obfuscation provided by the
compilation is a design requirement that extends from the need to keep
code proprietary in the commercial world. Speaking in purist terms,
the compaction benefit that it provides (or would provide in a
constrained environment) is outweighed by the inconvenience incurred
by the loss of interactivity in the development process.
It's interesting that the "big three" interpretive languages in the
open source world (Perl 6, Python, & Ruby) are starting to sprout
runtime systems of similar sophistication to JVM/.NET, and are getting
closer to having comparable performance. It shows very clearly that if
you don't care about source code obfuscation you can 'have your cake
and eat it too' ;-)
I very wise man I had a conversation with recently mentioned that
encrypted source was a better solution. I agree with this sentiment,
and believe it will not be too long before it becomes commonplace.
Matt
I think you're being serious and funny at the same time.
> Very good work though. I never would have expected anything Java within a
> stone throw (or serial cable) of an 8-bitter.
Lego mindstorm also have a Java engine in their small computers. It's a
very
restricted kind of Java though, it doesn't have a garbage collector and
because of this everything has to be static or atleast a known number of
instances.
That looks very good! Perhaps I've misjudged the compaction objectives
of the Java designers. (After all, it began life as a method for coding
for set-top boxes. ;-)
> Here is the best p-code description I could find.
>
> http://homepages.cwi.nl/~steven/pascal/book/10pcode.html
This is, I believe, the original CDC 6500 ETH P-code compiler, for which
code uniformity was a higher objective than compaction. The UCSD team
did many code compaction tunings to the bytecode.
In the early days of Windows (or indeed of *any* GUI), the performance
of the "raster ops" was the fundamental limiter on the speed of screen
changes. By all rights, this routine (and its uses) should have been
the full-time focus of a couple of brilliant engineers continuously
since the beginning of the project.
Forth and APL both have reputations (to their detractors) of being
"write-only languages". ;-)
A very reasonable restriction for a real-time environment...