Inaccuracies in "bytecode VM" article

516 views
Skip to first unread message

Charles Oliver Nutter

unread,
Dec 22, 2011, 11:50:57 PM12/22/11
to General Dart Discussion
I can't let this one slide :)

Your article on "Why Not A Bytecode VM" contains a multitude of
inaccuracies about the JVM. Even closer to my heart, it contains a
complete falsehood about JRuby.

http://www.dartlang.org/articles/why-not-bytecode/

Your claims, with rebuttal:

0. Hotspot versus JVM versus arbitrary bytecoded VMs

First, a general complaint: what JVM are you talking about here? They
all have different ways of optimizing. Some don't optimize at all.
Your use of "JVM" here is almost meaningless.

JVM is also just one example of a bytecoded VM. There are many others,
some of them designed for dynamic languages (e.g. Ruby 1.9, Rubinius,
Python, Parrot). You're basing a lot of your argument on the JVM (and
on incorrect statements about the JVM, at that).

From here we'll assume that by JVM you mean the reference
implementation, OpenJDK/Hotspot.

1. "performance is generally not on par with specialized VMs (see
JRuby or Rhino)."

JRuby has been one of the fastest Ruby runtimes for a few years now,
and with the addition of invokedynamic to the JVM it has made a big
leap even further ahead. JRuby is the fastest or one of the fastest
Ruby implementations today, and will continue to get faster in the
coming months as we make better use of invokedynamic.

2. JVM does not let you do what Java cannot do

This is blatantly false. JRuby is a very fast dynamic language on the
JVM with or without invokedynamic, and for a while now has been the
Ruby to beat when it comes to Ruby execution performance. This comes
on top of the fact that:

* We don't create a Java class for each Ruby class and have our own
class hierarchy and method table logic.
* Ruby has a limited form of multiple inheritance through mixins/
modules, which we implement correctly.
* Ruby's classes are mutable.

Furthermore, none of these things has *anything* to do with bytecode.
The JVM itself doesn't care if you create classes in the same way as
Java, or if you use a normal JVM class hierarchy at all.

3. A bytecode VM can't support all possible language features.

No VM or runtime can natively support all possible language feature.
Or, put another way, any VM can support all possible features. The
damn things are obviously turing complete, so saying that by using a
bytecode VM you can't implement some language feature is obviously
wrong.

Also, the "complexity" from adding new opcodes is generally blunted by
not adding new opcodes. The JVM instruction set has not changed
significantly in 15 years and has supported hundreds of languages --
many of them dynamic-typed -- during that time. invokedynamic is a new
addition, but a naive implementation of it adds very little VM
complexity. Yes, optimizing it adds complexity, but it's exposing
optimized dynamic call site binding to as a user-exposed API. You'd
expect that to take some heavy lifting to run fast.

4. A bytecode VM is more than just bytecode

You're not wrong here, but I don't see what the point is. Any runtime
you choose to target will have its own shape. Compiling to Javascript
works best when your feature set matches Javascript. If it doesn't you
have to work around the runtime. Compiling to NativeClient works best
if your feature set fits what NativeClient provides. If it doesn't,
you have to build your own stuff. Compiling to x86 works best if your
feature set fits x86. If it doesn't, you have to work around it. This
is pretty much a tautology...are you trying to say that there's some
runtime out there that can support all possible language features
equally well?

5. JVM can't optimize for non-statically-typed languages

Again, this is completely wrong. The JVM doesn't care about static
types. It just cares about objects and code. Ruby is dynamically
typed, but the JVM is able to inline across dynamic call boundaries,
optimize dynamically-typed code, and efficiently manage (and in some
cases eliminate) allocated objects. It is precisely because of this
that JRuby is able to perform so well.

I'll go toe-to-toe with anyone who claims the JVM has to be running a
statically-typed language to optimize, because I actually read the
assembly code it generates for JRuby on a regular basis.

6. The JVM is statically typed.

The JVM is not statically typed. http://blog.headius.com/2008/09/first-taste-of-invokedynamic.html

7. Allowing users to run their own bytecode opens up security holes.

You can't possibly be arguing that allowing users to run arbitrary
source is more secure than allowing users to run arbitrary bytecode,
can you? Language grammar can dictate no more than a bytecode
specification, and both are subject to the exact same sorts of
exploits. In fact, bytecode is likely *much* easier to secure because
the set of operations is considerably smaller. OpenJDK's bytecode
verifier has a rigorous proof to accompany it that *proves* it's
secure. Do you have such a thing for Dart? Can you make one? Now, can
you guarantee it will remain secure across all target runtimes?

---

Now, I'm not arguing with your primary point: that Dart is better
compiling to source, rather than to some kind of bytecoded VM. I'm not
arguing for it either...it's your choice, and the runtimes you intend
to target will certainly influence it. But the justifications you give
in this article are misleading at best and often completely wrong.

- Charlie

Seldaiendil D. Flourite

unread,
Dec 23, 2011, 3:54:01 AM12/23/11
to Charles Oliver Nutter, General Dart Discussion
I'm not a VM expert, but I think I can answer a few points:

0. Hotspot versus JVM versus arbitrary bytecoded VMs

First, a general complaint: what JVM are you talking about here? They
all have different ways of optimizing. Some don't optimize at all.
Your use of "JVM" here is almost meaningless.

JVM is also just one example of a bytecoded VM. There are many others,
some of them designed for dynamic languages (e.g. Ruby 1.9, Rubinius,
Python, Parrot). You're basing a lot of your argument on the JVM (and
on incorrect statements about the JVM, at that).

From here we'll assume that by JVM you mean the reference
implementation, OpenJDK/Hotspot.

I thought he was talking about the more extended JVM, after all if you distribute your code it will run on the client VM

1. "performance is generally not on par with specialized VMs (see
JRuby or Rhino)."

JRuby has been one of the fastest Ruby runtimes for a few years now,
and with the addition of invokedynamic to the JVM it has made a big
leap even further ahead. JRuby is the fastest or one of the fastest
Ruby implementations today, and will continue to get faster in the
coming months as we make better use of invokedynamic.

As I understand, you are saying JRuby is faster than Ruby. He says JRuby is not as fast as Java because the VM is specialiced for Java.

---
Seldaiendil

Peter Lawrey

unread,
Dec 23, 2011, 4:27:39 AM12/23/11
to General Dart Discussion
I would add that the rare occasion where the JVM doesn't or can't
support a feature, you can use JNI. One example for me is reading the
Time Stamp Counter directly (actually a assembly language instruction
even in C) While the JVM might be turning complete, there can be
occasions when you want to most efficient way of doing sometime e.g. a
time stamp which doesn't take longer than the thing you are
timing. ;)

BTW I know System.nanoTime() can use the TSC but its *much* slower
because its a system call which corrects for a number of factors like
using multiple sockets and drift.

Charles Oliver Nutter

unread,
Dec 23, 2011, 4:34:06 AM12/23/11
to General Dart Discussion
On Dec 23, 2:54 am, "Seldaiendil D. Flourite" <seldaiend...@gmail.com>
wrote:
> I thought he was talking about the more extended JVM, after all if you
> distribute your code it will run on the client VM

OpenJDK has a "tiered" mode now that can start up as fast as client
and optimize as well as server. It's like to be the standard, if Java
in the browser ever returns from the grave.

In any case, the failing of JVM developers to recognize and address
the needs of an in-browser VM have little bearing on whether "bytecode
VMs" are a good or bad idea.

> As I understand, you are saying JRuby is faster than Ruby. He says JRuby is
> not as fast as Java because the VM is specialiced for Java.

If that's so, then this is *also* wrong. JRuby with invokedynamic is
in many cases *as fast* as Java for making calls and walking data
structures. We do not yet compete on raw numeric performance, but it
has little to do with the fact that we're targeting a "bytecode
VM"...it's more the fact that the JVM has always had this non-OO
crutch of "primitives" to fall back on, and as a result they have not
until recently spent time optimizing fully-boxed numeric performance.
A "bytecode VM" designed from the beginning with no primitives and
with explicit intent to optimize object-based numerics would perform
very well, as will the JVM once they priorities boxed numeric
performance (which has already begun due to the popularity and success
of dynamically-typed languages on the JVM).

Let's not wander too far away from the original post here. I never
claimed that a Dart-specific VM couldn't run Dart faster than anything
else. In fact, I made it clear that this would likely be the case,
since all VMs must choose a feature set to optimize and that feature
set will not make all the people happy all of the time. I was simply
countering the FUD that somehow "bytecode VMs" are a bad idea and that
the JVM and languages built on it show the reasons why. Nothing could
be further from the truth; if anything, the JVM is a shining example
of why a "bytecode VM" is an incredibly *good* idea.

- Charlie

Charles Oliver Nutter

unread,
Dec 23, 2011, 5:31:40 AM12/23/11
to General Dart Discussion
On Dec 23, 3:27 am, Peter Lawrey <peter.law...@gmail.com> wrote:
> I would add that the rare occasion where the JVM doesn't or can't
> support a feature, you can use JNI.  One example for me is reading the
> Time Stamp Counter directly (actually a assembly language instruction
> even in C) While the JVM might be turning complete, there can be
> occasions when you want to most efficient way of doing sometime e.g. a
> time stamp which doesn't take longer than the thing you are
> timing. ;)

Indeed. And with OpenJDK, you can even hack apart the JVM if you like,
as folks have done to add tail calls, coroutines, and more.

> BTW I know System.nanoTime() can use the TSC but its *much* slower
> because its a system call which corrects for a number of factors like
> using multiple sockets and drift.

Cliff Click, of Hotspot and Azul fame, has an excellent talk where he
explains all the problems with trying to get truly accurate times on
modern systems. The bottom line is that you can only do it with a
performance hit, but you probably don't need "perfect" timing most of
the time anyway. And I've actually been bitten by one of his cases:
Hardware VMs like VirtualBox (and perhaps Xen and its kin) often have
to emulate accurate system timing through complicated synchronization
guarantees. As a result, even System.currentTimeMillis is slow when
running atop VirtualBox.

In any case, I want to keep beating my original drum: I don't claim
Dart shouldn't have a specialized VM...I just claim that the reasons
given to justify avoiding "bytecode VMs" miss the mark.

Andrew Jones

unread,
Dec 23, 2011, 6:07:33 AM12/23/11
to General Dart Discussion
> You can't possibly be arguing that allowing users to run arbitrary
> source is more secure than allowing users to run arbitrary bytecode,
> can you? Language grammar can dictate no more than a bytecode
> specification, and both are subject to the exact same sorts of
> exploits. In fact, bytecode is likely *much* easier to secure because
> the set of operations is considerably smaller. OpenJDK's bytecode
> verifier has a rigorous proof to accompany it that *proves* it's
> secure. Do you have such a thing for Dart? Can you make one? Now, can
> you guarantee it will remain secure across all target runtimes?

There are more combinations of bytecodes of a particular set of
bytecodes then there are combinations of bytecodes that can be
generated by a particular language.

I don't like the idea of a bytecode VM because that still leaves the
problem of a language that needs to be designed that is better than
the current languages in terms of web development. I find Dart much
more appealing then Ruby. I also don't like the idea of fragmentation.
The web is popular because we were all forced to use the same things.

Jedediah Smith

unread,
Dec 23, 2011, 6:11:23 AM12/23/11
to General Dart Discussion


On Dec 23, 3:54 am, "Seldaiendil D. Flourite" <seldaiend...@gmail.com>
wrote:
> As I understand, you are saying JRuby is faster than Ruby. He says JRuby is
> not as fast as Java because the VM is specialiced for Java.

No, Google is saying JVM implementations of languages are not on par
with their native interpreters, which is wrong, at least in the case
of JRuby. Moreover, it suggests that the Dart team hasn't done their
homework, which is a bit concerning if they are trying to create *the*
next programming language for the web.
Message has been deleted

Rodrigo Moraes

unread,
Dec 23, 2011, 7:47:32 AM12/23/11
to General Dart Discussion
On Dec 23, 9:11 am, Jedediah Smith wrote:
> No, Google is saying JVM implementations of languages are not on par
> with their native interpreters, which is wrong, at least in the case
> of JRuby.

I think there's a misunderstanding here. The JRuby case is probably
exceptional; it is the Ruby VM is that is not on par with numerous
examples of dedicated dynamic language engines that outperform the
ones built on top of existing statically-typed VMs. The intention was
not to offend the JRuby folks who seem to be doing an excellent
job. :)

-- rodrigo

vivo

unread,
Dec 23, 2011, 8:09:22 AM12/23/11
to General Dart Discussion
One addition:

"The biggest advantage of a bytecode VM is that it is not restricted
to one input language."

I always thought the biggest advantage is that it easier to port the
language to different OS and hardware platforms, because only the VM
has to be ported; all programs (in the best case even the compiler)
are already compiled to Byte Code and will therfore run on the newly
ported VM.

Bob Nystrom

unread,
Dec 23, 2011, 12:18:58 PM12/23/11
to Charles Oliver Nutter, General Dart Discussion
Well, so much for a relaxing holiday break without thinking about Dart... ;)

Let me start by saying very clearly that it wasn't our intent to criticize JRuby. I think it's a great project, and, in particular, I've learned a lot about languages and VMs from your articles about it, Charlie.

There's been a lot of confusion about what we were trying to accomplish with this article, which I take responsibility for. I think I usually do a pretty good job explaining things but this time... maybe not so much.

Maybe what's missing is the context that we assumed most readers would have. When we announced Dart, there were *dozens* of comments all over the interwebs from people saying we were utter imbeciles for not making a bytecode VM, and in particular some magical "universal" bytecode VM. Many of these people had zero idea why anyone would *ever* consider language specific VM.

My goal with this article was just to show that bytecode VMs (and in particular hypothetical "universal" bytecode VMs) are not a panacea and that dedicated language VMs actually do have advantages that many have overlooked. I think you wouldn't disagree with either of those points in general, though our presentation of them seems to have been off the mark.

First, a general complaint: what JVM are you talking about here?

We only intended to use the JVM as an example of *some* bytecode VM because it's a concrete point of reference for people. Our points were intended to be general enough that specific JVMs wouldn't matter.

There are many others, some of them designed for dynamic languages (e.g. Ruby 1.9, Rubinius, Python, Parrot).

Right, but none of those are as well known as the JVM so maybe not as useful as an illustrative example. No matter what example we'd used here, people would have called it a strawman so I'm not sure how much it would have helped to mention those.

1. "performance is generally not on par with specialized VMs (see JRuby or Rhino)." JRuby has been one of the fastest Ruby runtimes for a few years now, and with the addition of invokedynamic to the JVM it has made a big leap even further ahead. JRuby is the fastest or one of the fastest Ruby implementations today

Right, this is a point I failed to express clearly. JRuby is awesome! It's very fast compared to other Ruby implementations at getting faster. However, I'm not sure if that says more about JRuby or about other Ruby implementations.

What we should have said here is "performance is generally not on par with specialized VMs (see V8 versus Rhino)". I'm no benchmark expert, but as far as I can tell, mature VMs dedicated to dynamic languages (V8, TraceMonkey, JSCore, Racket, Lua) are generally faster than dynamic languages running on existing VMs.

Our intent with this point was to show that if your goal is a fast dynamic language (which ours is), just taking the JVM and cramming it in a browser isn't an obvious smart decision.

This doesn't mean we couldn't have designed a *dynamic* language bytecode format from scratch, built that VM, and then designed Dart on top of that and gotten good performance. That's hypothetically possible but, as you can imagine, a hell of a lot more work.

2. JVM does not let you do what Java cannot do 

Well, obviously you can get whatever semantics you want on whatever base you want: Turing tarpit and all that. What you can't guarantee is that you can do that efficiently. The article does clarify that:

Sometimes you can get around "missing" opcodes by compiling to other existing ones, but often that's impossible while still getting good performance. Tail-call elimination, continuations (call/cc), eval(), floats, and long doubles require specialized opcodes to be fast.

The "to be fast" part is key. I know how to compile non-local returns to JavaScript right now. What I don't know how to do is compile them to JS that's fast enough to not make me regret using them. Sure, you can not use classes in the JVM, or you can roll your own unsigned math. As far as I know, you can't do that without adding a lot of overhead.

This says a lot about the DNA of the Dart team, but our philosophy is "slow but possible" is equivalent to "not possible".

You're not wrong here, but I don't see what the point is. Any runtime you choose to target will have its own shape.

The high level point here is that a VM is high level by making a set of assumptions about the language(s) that will run on top of it. When those assumptions line up with your language, great. Otherwise, you start losing performance because of the impedence mismatch.

Here, we just wanted to make sure people realized VMs dictate more than just a set of opcodes: they also mandate all sorts of other things like a memory model, concurrency primitives, file structure, loading semantics, etc. Any of those can end up being a bad fit for your language.

are you trying to say that there's some runtime out there that can support all possible language features equally well? 

Definitely not. We're trying to respond to the assertion others have made that you *can* do that. Look around, you'll find lots of people saying the web needs a "universal" bytecode VM. (Alas, I haven't seen any proposals for what the actual instruction set for that would be. ;) )

You can't possibly be arguing that allowing users to run arbitrary source is more secure than allowing users to run arbitrary bytecode, can you?

The article does claim that, yes. I'm neither a VM nor a security expert, but we based that from talking to several people with lots of JVM experience. My very simplistic understanding is this:

The JVM is (as you noted in your linked article) untyped at its core. That means ill-formed bytecode can trash the stack, access memory outside of it, or reinterpret bits on it as a different. All of that sounds bad to me.

To get around that, JVMs do bytecode verification, which I think is somewhere between a theorem prover and an abstract interpreter for a stack-based language.

Dart doesn't have to do that. The runtime itself is dynamically typed (dynamically typed, in that operations are checked at runtime, not *untyped* like the JVM). The only input into the VM is Dart source code. That means things like "trash the stack" or "reinterpret bits on the stack" aren't even meaningful.

But the justifications you give in this article are misleading at best and often completely wrong. 

It definitely wasn't my intent to mislead, and maybe the article tries to make its points more strongly than it should have. I really appreciate feedback like yours to give some balance and other viewpoints to this. Things like "bytecode vs language VM" are incredibly high-level decisions with many many factors that get involved. I don't think any short article, no matter how well written, can do the topic justice, but follow-up criticism like this helps a lot.

Cheers and happy holidays!
- bob

Sleepy Daddy Software

unread,
Dec 23, 2011, 2:47:58 PM12/23/11
to General Dart Discussion
I wouldn't pretend to be an expert on VMs and byte-code vs direct-from-
source-code performance.

But I'd like to add my 2 cents. As a developer, I just don't want to
be pigeonholed into using one programming language, and one
programming language only, for any platform. It doesn't matter how
good the programming language is. It doesn't matter how fast code
written in that language run on that particular runtime. As a
developer, I want to use the best tool for the job, and no one
language will ever be the best tool for every job. The web is not just
for "web apps" anymore. The web is for games, productivity, office
apps, everything.

Now, I may not be an expert, but I can see two things:

1) There are lots of programming languages that run pretty fast on the
JVM and the CLR, both byte-code based virtual machines, and although
neither were initially designed with dynamic languages in mind, both
have added functionality that helps dynamic languages run faster.
There are multiple examples of dynamic languages that run either
within 5% of their "native" VM's performance, or in the case of JRuby,
the byte-code VM exceeds the native one. Most of these languages also
run on the VM with few if any limitations in the source language.

2) There are very few programming languages that run pretty fast after
being cross-compiled to JavaScript, unless the language is itself
DESIGNED to be cross-compiled to JavaScript. Some don't even support
the full language functionality. Also, if your source language is
statically typed, you should probably not expect to get anywhere near
the same performance as your code running natively.

So, given those observations, I have serious doubts that Dart, as a
dynamic language VM with no byte-code option, would be any better at
running arbitrary cross-compiled code than JavaScript is.

Maxim Kizub

unread,
Dec 23, 2011, 3:37:26 PM12/23/11
to General Dart Discussion

Bob Nystrom:
> This says a lot about the DNA of the Dart team, but our philosophy is "slow
> but possible" is equivalent to "not possible".
...
> Dart doesn't have to do that. The runtime itself is dynamically typed
> (dynamically typed, in that operations are checked at runtime, not
> *untyped* like the JVM). The only input into the VM is Dart source code.
> That means things like "trash the stack" or "reinterpret bits on the stack"
> aren't even meaningful.

Am I correct, and Dart's "fast" means "a bit faster then JavaScript"?
I asked a day ago, for what kind of applications Dart is targeted, and
I was
told - for all kind, web scripts, server and mobile apps... Now I
don't know
what to think... You are seriously talking about using dynamically
typed
execution environment targeted for servers and mobile market?!
JVM makes type checks only once, during verification, and then run
at full speed. While Dart's VM will do the checks for every operation
and
method invoccation - this will be slower, then compilation of Dart's
(typed)
code into JVM's bytecode. And for next dosen of years - JVM will be
faster for dynamic code too. Just because of huge science and
financial
investments into VJM/JIT optimization.

Charles Oliver Nutter

unread,
Dec 23, 2011, 4:00:31 PM12/23/11
to General Dart Discussion
I'll inline reply here, since I've had my Reddit flamewar fun for the
month.

On Dec 23, 11:18 am, Bob Nystrom <rnyst...@google.com> wrote:
> Well, so much for a relaxing holiday break without thinking about Dart... ;)
>
> Let me start by saying very clearly that it wasn't our intent to criticize
> JRuby. I think it's a great project, and, in particular, I've learned a lot
> about languages and VMs from your articles about it, Charlie.

Well, I appreciate that.

> There's been a lot of confusion about what we were trying to accomplish
> with this article, which I take responsibility for. I think I usually do a
> pretty good job explaining things but this time... maybe not so much.
>
> Maybe what's missing is the context that we assumed most readers would
> have. When we announced Dart, there were *dozens* of comments all over the
> interwebs from people saying we were utter imbeciles for not making a
> bytecode VM, and in particular some magical "universal" bytecode VM. Many
> of these people had zero idea why anyone would *ever* consider language
> specific VM.
>
> My goal with this article was just to show that bytecode VMs (and in
> particular hypothetical "universal" bytecode VMs) are not a panacea and
> that dedicated language VMs actually do have advantages that many have
> overlooked. I think you wouldn't disagree with either of those points in
> general, though our presentation of them seems to have been off the mark.

As another commenter on Reddit pointed out: I think you were a bit
vague about these two points, which are largely separate.

I agree that a dedicated VM can often be faster than a general-purpose
VM...I don't think anyone would try to argue against that, since a
dedicated VM can obviously focus efforts more narrowly. We can look at
Parrot as a perfect example of what happens when you try to build a
general-purpose VM that tries to do what everyone might ever want of
it.

I don't agree with the implication (intentional or not) that there's
something more wrong with bytecode VMs than with any other type of VM.
I sympathize with your desire to quiet the peanut gallery; they can be
deafening and distracting. But I would have preferred an article that
made a clear point-by-point case as to why Dart's chosen VM design is
*good* rather than why some other design -- and specifically, why some
other VM -- is bad. The article has an overwhelmingly negative tone to
me, and I'm not the only one that got that impression.

> First, a general complaint: what JVM are you talking about here?
>
> We only intended to use the JVM as an example of *some* bytecode VM because
> it's a concrete point of reference for people. Our points were intended to
> be general enough that specific JVMs wouldn't matter.
>
> There are many others, some of them designed for dynamic languages (e.g.
>
> > Ruby 1.9, Rubinius, Python, Parrot).
>
> Right, but none of those are as well known as the JVM so maybe not as
> useful as an illustrative example. No matter what example we'd used here,
> people would have called it a strawman so I'm not sure how much it would
> have helped to mention those.

Perhaps so, but the article largely came off as JVM-bashing. If you
know me, you'll know I generally don't sit down for that sort of
thing, especially when it additionally calls out JRuby as an
example ;)

> 1. "performance is generally not on par with specialized VMs (see JRuby or
>
> > Rhino)." JRuby has been one of the fastest Ruby runtimes for a few years
> > now, and with the addition of invokedynamic to the JVM it has made a big
> > leap even further ahead. JRuby is the fastest or one of the fastest Ruby
> > implementations today
>
> Right, this is a point I failed to express clearly. JRuby is awesome! It's
> very fast compared to other Ruby implementations at getting faster.
> However, I'm not sure if that says more about JRuby or about other Ruby
> implementations.

I misinterpreted this as being "JRuby's not as fast as other Ruby
implementations designed for Ruby". You can see how I'd arrive there.

> What we should have said here is "performance is generally not on par with
> specialized VMs (see V8 versus Rhino)". I'm no benchmark expert, but as far
> as I can tell, mature VMs dedicated to dynamic languages (V8, TraceMonkey,
> JSCore, Racket, Lua) are generally faster than dynamic languages running on
> existing VMs.
>
> Our intent with this point was to show that if your goal is a fast dynamic
> language (which ours is), just taking the JVM and cramming it in a browser
> isn't an obvious smart decision.

I should have also pointed out that JRuby is not just faster than
other Ruby implementations...it's now approaching Java performance due
to invokedynamic brushing aside the dynamic call overhead. That would
have answered your point more clearly. Invokedynamic really is a game-
changer, and it's an excellent example of the power hidden inside
modern JVMs that's just screaming to get out. It is now feasible that
JRuby could, with the exception of numeric performance, be just as
fast as any statically-typed language on the JVM. Even greater, it
could be as fast or faster than dynamic language runtimes like V8. You
should be careful trying to assert that JRuby won't or can't get
there, because it's already happening.

> This doesn't mean we couldn't have designed a *dynamic* language bytecode
> format from scratch, built that VM, and then designed Dart on top of that
> and gotten good performance. That's hypothetically possible but, as you can
> imagine, a hell of a lot more work.

Knowing what I know about the JVM and invokedynamic, I would be very
surprised if Dart couldn't run incredibly well there. Dart is
massively simpler at its core than Ruby, and I'm starting to see near-
Java speeds with Ruby...so Dart ought to be a cakewalk.

> 2. JVM does not let you do what Java cannot do
>
> Well, obviously you can get whatever semantics you want on whatever base
> you want: Turing tarpit and all that. What you can't guarantee is that you
> can do that *efficiently*. The article does clarify that:
>
> Sometimes you can get around "missing" opcodes by compiling to other
>
> > existing ones, but often that's impossible while still getting good
> > performance. Tail-call elimination, continuations (call/cc), eval(),
> > floats, and long doubles require specialized opcodes to be fast.
>
> The "to be fast" part is key. I know how to compile non-local returns to
> JavaScript right now. What I don't know how to do is compile them to JS
> that's fast enough to not make me regret using them. Sure, you can not use
> classes in the JVM, or you can roll your own unsigned math. As far as I
> know, you can't do that without adding a lot of overhead.
>
> This says a lot about the DNA of the Dart team, but our philosophy is "slow
> but possible" is equivalent to "not possible".

I don't disagree. Many things JRuby has had to emulate over the years
ended up being slower than in purpose-built Ruby VMs. However, I fell
you strayed away from your central point here. That the JVM doesn't
appear to give you some of the features you want is irrelevant to
whether you build a bytecode VM for Dart or not. The JVM itself is
changing, and if you'd have written this article 5 years ago you would
have had to omit mention of invokedynamic. Here are the facts as I
know them:

* For what it already does well, OpenJDK is really, really hard to
beat. What it does well (object management and method invocation)
often lines up with a large portion of almost any language. JRuby has
parts that may always be slower because we can't directly add fields
to a given call frame. It turns out, however, that we can optimize so
much other code it doesn't matter.

* For what it doesn't do well, there's projects in progress, planned,
or at least possible because of the open codebase. For example,
there's a working coroutine patch that JRuby actually allows users to
leverage in its "Fiber" implementation. There's a tail calls patch
that works already. There's in-progress patches for value/struct types
and fixnums. What else would you like? The core of OpenJDK does not
specifically limit any of the features you might want. Sure, they're
not here today. But they're also not impossible, and some are right
around the corner. Is it worth helping out in those areas to get all
the awesome parts of OpenJDK that *are* available right now?

> You're not wrong here, but I don't see what the point is. Any runtime you
>
> > choose to target will have its own shape.
>
> The high level point here is that a VM is high level by making a set of
> assumptions about the language(s) that will run on top of it. When those
> assumptions line up with your language, great. Otherwise, you start losing
> performance because of the impedence mismatch.
>
> Here, we just wanted to make sure people realized VMs dictate more than
> just a set of opcodes: they also mandate all sorts of other things like a
> memory model, concurrency primitives, file structure, loading semantics,
> etc. Any of those can end up being a bad fit for your language.

That's certainly true. You should have said it that way.

> are you trying to say that there's some runtime out there that can support
>
> > all possible language features equally well?
>
> Definitely not. We're trying to respond to the assertion others have made
> that you *can* do that. Look around, you'll find lots of people saying the
> web needs a "universal" bytecode VM. (Alas, I haven't seen any proposals
> for what the actual instruction set for that would be. ;) )

I don't care about those other people, and I don't really care if Dart
uses a bytecode VM or not (except for the fact that a new "bytecode
for the web" would give me a fun possible future implementing
languages atop it). I think you tried to answer too many different
questions in the post. Again, I wish you would have said it like
you're saying it here, rather than turning into "Look! The JVM doesn't
have feature X! Q.E.D."

> You can't possibly be arguing that allowing users to run arbitrary source
>
> > is more secure than allowing users to run arbitrary bytecode, can you?
>
> The article does claim that, yes. I'm neither a VM nor a security expert,
> but we based that from talking to several people with lots of JVM
> experience. My very simplistic understanding is this:
>
> The JVM is (as you noted in your linked article) untyped at its core. That
> means ill-formed bytecode can trash the stack, access memory outside of it,
> or reinterpret bits on it as a different. All of that sounds bad to me.
>
> To get around that, JVMs do bytecode verification, which I think is
> somewhere between a theorem prover and an abstract interpreter for a
> stack-based language.
>
> Dart doesn't have to do that. The runtime itself is dynamically typed
> (dynamically typed, in that operations are checked at runtime, not
> *untyped* like the JVM). The only input into the VM is Dart source code.
> That means things like "trash the stack" or "reinterpret bits on the stack"
> aren't even meaningful.

No code representation will be ungameable. If your intermediate format
is going to be an AST, then I can produce ASTs that wouldn't otherwise
come out of your grammar. If you'll have no intermediate format, then
I can find some other way to exploit bugs in your grammar or compiler
to produce bad ASTs.

Bytecode does indeed need to be verified, but the same code for any
situation where you're going to be running arbitrary code. In your
case, you're not actually getting around the issue...either you need
to verify that the intermediate format is represented correctly, or
the compiler that turns the AST into e.g. JavaScript will do it, or at
the end of the day the runtime on which you execute the JavaScript
will do it. There's no escaping the verification process...you're just
dodging the question by having someone else do it. I do the same in
JRuby, but I won't try to claim that because we interpret an AST and
compile to Someone Else's Intermediate Format that we've avoided
dealing with verification.

> But the justifications you give in this article are misleading at best and
>
> > often completely wrong.
>
> It definitely wasn't my intent to mislead, and maybe the article tries to
> make its points more strongly than it should have. I really appreciate
> feedback like yours to give some balance and other viewpoints to this.
> Things like "bytecode vs language VM" are incredibly high-level decisions
> with many many factors that get involved. I don't think any short article,
> no matter how well written, can do the topic justice, but follow-up
> criticism like this helps a lot.

Hopefully you'll do something to address the article itself. I don't
think it reflects well on the Dart team, and it's clear that I'm not
the only one who got the wrong impression from it.

And pelase remove JRuby from your examples or use it to show that the
JVM actually does support dynamic invocation very well now.

- Charlie

John Messerly

unread,
Dec 23, 2011, 5:22:01 PM12/23/11
to Charles Oliver Nutter, General Dart Discussion
Charlie, I can't square what you're saying here about JRuby performance with the shootout numbers.

My reading is:

JRuby roughly on part with MRI on throughput (much worse on memory):

For the most part behind V8 (often by 10x, except pidigits where that's reversed):

Are those benchmarks perhaps running an older versions of JRuby (e.g. pre-invokedynamic)? I can certainly believe invokedynamic is a huge help.

But the claim that Ruby can be as fast as Java is ... very surprising to me, having seen the difficulty of implementing Ruby, and talking to many (smarter than me) VM implementers.

The bytecode vs language decision for Dart predates my employment at Google, but having worked a bit on DLR/IronPython/IronRuby nothing in the article seemed very off the mark, at least if you replace "JVM" with "CLR". I doubt you could get a language like JS (as an example) to run nearly as fast on CLR compared with the native engines.

Cheers,
- John

Isaac Gouy

unread,
Dec 23, 2011, 9:47:36 PM12/23/11
to General Dart Discussion


On Dec 23, 5:22 pm, John Messerly <jmesse...@google.com> wrote:
>
> Are those benchmarks perhaps running an older versions of JRuby (e.g.
> pre-invokedynamic)? I can certainly believe invokedynamic is a huge help.

The u32(x86) benchmarks game measurements are for the latest JRuby
release and the latest JVM release.

I believe Charlie is talking about what he sees with the latest
greatest unreleased JRuby version available to him.

Stephen Haberman

unread,
Dec 23, 2011, 10:21:51 PM12/23/11
to Bob Nystrom, Charles Oliver Nutter, General Dart Discussion

> There's been a lot of confusion about what we were trying to
> accomplish with this article, which I take responsibility for. I
> think I usually do a pretty good job explaining things but this
> time... maybe not so much.

Very tangentially, I always thought this post from back in the day
was a good way to explain the "why no VM" stance of DART:

https://groups.google.com/a/dartlang.org/group/misc/msg/5f86f14a4961e5b7

It made sense to me anyway. I was surprised that more of that posts
points didn't make it into the article. It's less "bytecode VMs are
bad" and more "bytecode VMs don't work for today's JS developers
because they expect the browser to compile/debug/run the source
anyway".

- Stephen

justn...@gmail.com

unread,
Dec 23, 2011, 11:16:25 PM12/23/11
to mi...@dartlang.org
Iron Python has also been reported to be quite fast, if not faster than non-Iron Python in some benchmarks. It's also a dynamic language like JRuby but on .net, a different statically-typed VM. The evidence seems pretty clear that you can get quite excellent performance out of byte-code based VM's even for static languages.

justn...@gmail.com

unread,
Dec 23, 2011, 11:19:17 PM12/23/11
to mi...@dartlang.org
There are many advantages. I like yours too, but being amenable to multiple higher-level languages is very nice as well.

justn...@gmail.com

unread,
Dec 23, 2011, 11:39:16 PM12/23/11
to mi...@dartlang.org, Charles Oliver Nutter
This doesn't mean we couldn't have designed a *dynamic* language bytecode format from scratch, built that VM, and then designed Dart on top of that and gotten good performance. That's hypothetically possible but, as you can imagine, a hell of a lot more work."

Yes please do this :)

But it seems like more work if you're only going to be targeting a single platform and write a single language. If you have N languages and M platforms then it ends up being more work to not build that VM.

I think what we're seeing is people worrying about fragmentation of the web. We see languages sitting on top of javascript  (such as coffee script) and languages going around javascript (such as dart) and other people who want to see their own languages in their browser... it's all natural different languages are better suited for different jobs but it's either sub-par to sit on top of javascript or fragmenting to go around it, so a lower level platform neutral byte-code sounds like an ideal solution. I mean why are you writing Dart at all, if javascript in V8 is so dang performant or perfect?

You mention byte code verification as a negative, but isn't that faster still than compiling code all the way down from text? Also how about average size of bytecode vs. original source? Time spent transferring code on the wire is an important part of performance too.


Ladislav Thon

unread,
Dec 24, 2011, 6:13:35 AM12/24/11
to mi...@dartlang.org
It seems to me that most of the article in fact doesn't discuss bytecode-based VM vs. source-level VM, but designing a Dart-specific VM vs. using/designing a general multilingual VM. The difference might be subtle, but is in fact very important. You could still design and build specialized VM for Dart that would be working on bytecodes, but since you are (among others) targeting the web, it actually doesn't make sense -- people are now used to in-browser debugging, and for that, you need the source code in the browser anyway. That is how I understand it.

And I think we shouldn't care about people that are complaining about Dart not being an universal VM [for the web] -- that is an extremely huge task, way out of scope of Dart.

LT

Florian Loitsch

unread,
Dec 24, 2011, 7:05:35 AM12/24/11
to Charles Oliver Nutter, General Dart Discussion
Let's start with the important thing: sorry about the JRuby confusion. It was never my intend to make JRuby (or Ruby for that matter) appear in a bad light. Apparently JRuby is as fast as the native Ruby VM. Something I should have checked. To me that means that the native VM is not optimized yet, but it is still a bad example.

Before responding inline, a general remark: the biggest complaint we get for choosing a language VM is that it doesn't (as easily) support other languages. Many people (even on this thread) would have preferred a bytecode VM in the hope that their favorite language could be compiled on it. This article is mainly directed towards them. We want to show that such a VM is either extremely (too) complex, or slow, or wouldn't be able to nicely accept their favorite language anyways. The problem is that most developers come to the discussion with unrealistic assumptions about bytecode VMs. A good part of the article is therefore spent discussing the "bad" parts of bytecode VMs.

On Fri, Dec 23, 2011 at 05:50, Charles Oliver Nutter <hea...@headius.com> wrote:
I can't let this one slide :)

Your article on "Why Not A Bytecode VM" contains a multitude of
inaccuracies about the JVM. Even closer to my heart, it contains a
complete falsehood about JRuby.

http://www.dartlang.org/articles/why-not-bytecode/

Your claims, with rebuttal:

0. Hotspot versus JVM versus arbitrary bytecoded VMs

First, a general complaint: what JVM are you talking about here? They
all have different ways of optimizing. Some don't optimize at all.
Your use of "JVM" here is almost meaningless.

JVM is also just one example of a bytecoded VM. There are many others,
some of them designed for dynamic languages (e.g. Ruby 1.9, Rubinius,
Python, Parrot). You're basing a lot of your argument on the JVM (and
on incorrect statements about the JVM, at that).

From here we'll assume that by JVM you mean the reference
implementation, OpenJDK/Hotspot.

1. "performance is generally not on par with specialized VMs (see
JRuby or Rhino)."

JRuby has been one of the fastest Ruby runtimes for a few years now,
and with the addition of invokedynamic to the JVM it has made a big
leap even further ahead. JRuby is the fastest or one of the fastest
Ruby implementations today, and will continue to get faster in the
coming months as we make better use of invokedynamic.
As mentioned above: sorry about that.
I still believe, though, that a native Ruby implementation can be much faster. 

2. JVM does not let you do what Java cannot do

This is blatantly false. JRuby is a very fast dynamic language on the
JVM with or without invokedynamic, and for a while now has been the
Ruby to beat when it comes to Ruby execution performance. This comes
on top of the fact that:

* We don't create a Java class for each Ruby class and have our own
class hierarchy and method table logic.
* Ruby has a limited form of multiple inheritance through mixins/
modules, which we implement correctly.
* Ruby's classes are mutable.

Furthermore, none of these things has *anything* to do with bytecode.
The JVM itself doesn't care if you create classes in the same way as
Java, or if you use a normal JVM class hierarchy at all.

This one has been answered by Bob. 

3. A bytecode VM can't support all possible language features.

No VM or runtime can natively support all possible language feature.
Or, put another way, any VM can support all possible features. The
damn things are obviously turing complete, so saying that by using a
bytecode VM you can't implement some language feature is obviously
wrong.

Also, the "complexity" from adding new opcodes is generally blunted by
not adding new opcodes. The JVM instruction set has not changed
significantly in 15 years and has supported hundreds of languages --
many of them dynamic-typed -- during that time. invokedynamic is a new
addition, but a naive implementation of it adds very little VM
complexity. Yes, optimizing it adds complexity, but it's exposing
optimized dynamic call site binding to as a user-exposed API. You'd
expect that to take some heavy lifting to run fast.

The JVM is not a good compilation target for general languages, and in particular dynamic languages. It is getting better (due to all kinds of optimizations and invokedynamic), but it never was a VM designed accept a multitude of languages.

4. A bytecode VM is more than just bytecode

You're not wrong here, but I don't see what the point is. Any runtime
you choose to target will have its own shape. Compiling to Javascript
works best when your feature set matches Javascript. If it doesn't you
have to work around the runtime. Compiling to NativeClient works best
if your feature set fits what NativeClient provides. If it doesn't,
you have to build your own stuff. Compiling to x86 works best if your
feature set fits x86. If it doesn't, you have to work around it. This
is pretty much a tautology...are you trying to say that there's some
runtime out there that can support all possible language features
equally well?
This, again, was targeted towards developers that want to see their favorite language compiled to the Web. 

5. JVM can't optimize for non-statically-typed languages

Again, this is completely wrong. The JVM doesn't care about static
types. It just cares about objects and code. Ruby is dynamically
typed, but the JVM is able to inline across dynamic call boundaries,
optimize dynamically-typed code, and efficiently manage (and in some
cases eliminate) allocated objects. It is precisely because of this
that JRuby is able to perform so well.

I'll go toe-to-toe with anyone who claims the JVM has to be running a
statically-typed language to optimize, because I actually read the
assembly code it generates for JRuby on a regular basis.

6. The JVM is statically typed.

The JVM is not statically typed. http://blog.headius.com/2008/09/first-taste-of-invokedynamic.html

7. Allowing users to run their own bytecode opens up security holes.

You can't possibly be arguing that allowing users to run arbitrary
source is more secure than allowing users to run arbitrary bytecode,
can you? Language grammar can dictate no more than a bytecode
specification, and both are subject to the exact same sorts of
exploits. In fact, bytecode is likely *much* easier to secure because
the set of operations is considerably smaller. OpenJDK's bytecode
verifier has a rigorous proof to accompany it that *proves* it's
secure. Do you have such a thing for Dart? Can you make one? Now, can
you guarantee it will remain secure across all target runtimes?
The point was that the AST for language VMs is saner than the one for bytecodes (depending on how low-level the bytecode is). The input of a structured-language VM must, by definition, be structured. That's not the case for bytecodes. The flexibility you get with bytecodes also makes the JIT more complex. It has to deal with control-flow it wouldn't have been able to see otherwise. Probably a source of subtle bugs.

// florian


---

Now, I'm not arguing with your primary point: that Dart is better
compiling to source, rather than to some kind of bytecoded VM. I'm not
arguing for it either...it's your choice, and the runtimes you intend
to target will certainly influence it. But the justifications you give
in this article are misleading at best and often completely wrong. 

- Charlie




--
Give a man a fire and he's warm for the whole day,
but set fire to him and he's warm for the rest of his life. - Terry Pratchett

unread,
Dec 24, 2011, 7:44:44 AM12/24/11
to General Dart Discussion
I agree with the "Why Not A Bytecode VM" article.

From performance viewpoint, a JVM does *not* fit the Ruby language.
Java bytecode features a constrained type system. An example of this
would be: compare http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_stdtypes.html
and the section "Types and values" in the JVM specification
http://java.sun.com/docs/books/jvms/second_edition/html/Concepts.doc.html#22930.

The key to maximum run-time performance of any programming language is
that it is running on a machine that executes instructions without
asking questions. If the compiler says "do 32-bit addition of these
two 32-bit numbers", the machine has to blindly execute it
irrespective of what those 32-bit numbers might be representing.
Ideally, any piece of data is just an array of bits and it has no
other type beyond this.

An abstract machine performing code verification in respect to some
kind of a constrained type system (example: JVM) can only lead to
performance issues, sometimes to serious performance issues. There are
cases when your compiler would like the program do execute instruction/
bytecode X (and it is safe to execute it), but the constrained VM does
not allow X because the VM does not understand that X makes sense and
is safe.

A universal high-performance bytecode VM with code verification is
very close to being a contradiction. Universality by definition
implies that some of the rules for achieving max performance as well
as some of the rules for verifying/achieving code correctness lay
outside of the VM specification. That is, those missing rules aren't
and cannot be in the VM specification.
> The JVM is not statically typed.http://blog.headius.com/2008/09/first-taste-of-invokedynamic.html

Rémi Forax

unread,
Dec 24, 2011, 11:47:27 AM12/24/11
to mi...@dartlang.org
So you start a discussion about VMs when I was away from internet,
tssss.

I've seen a lot of false assumptions in the two camps, pro/against-bytecode VMs.

First, V8 and the JVM are the same 'class' (like 'class' of submarine).
They both use multi-tiered compilers, with a good generational GC, a SSA internal form and a lot of similar optimisations like profiling, guard checks, inlining cache, optimistic assumption, deoptimization, loop optimizations (unrolling, hoisting etc).

The difference I see are more from their roots, V8 is a 'client' VM because it runs javascript in the browser so the optimizations are implemented to don't require to know a lot of informations before optimizing. The JVM is a 'server' VM so optimizations are implemented to generate faster code but  after profiling the code a long time. 
This is not fully true because Google is willing V8 (or it's descendant) to be used a server VM and Oracle wants  JVM to be used as a client VM.

Is a VM good to execute an existing dynamic language ?
I think the answer is NO !, because Python, Ruby or Javascript semantics use the assumption that there is an interpreter somewhere, so mapping a language designed with an interpreter in mind when you have a VM is sometimes daunting.
That's why Dart is interesting, because it's the first 'mainstream' dynamic language not designed around an interpreter.

From the performance point of view, is a bytecode VM better than a source based VM. I think the question is moot because you can easily transform a source code to an AST to a bytecode and a bytecode to an AST. In fact, if you take a look to the JVM, the bytecode is used by the JIts as an AST and not as a runnable code.

So what's the difference. The only difference I see is in the way things evolve.
Bytecode VMs require to froze the bytecode, you can enhance it, but it will require to update most of the tools of your eco-system. In the Java ecosystem, the bytecode evolve only twice in more than 15 years.
Source VMs evolve more easily but it makes thing harder if you want to write tools.

In conclusion, I'm not sure the difference worth a long thread like this one :)

cheers,
Rémi

jesse rose

unread,
Dec 25, 2011, 3:44:01 PM12/25/11
to General Dart Discussion
I suggest pulling native optimization out of the JVM and watch your
byte code crawl.

Seth is correct, Dart wisely decided to skip the middle man, run
native, and finally fill the void Java/JRuby could never fill.

In any event, byte code works best on servers that don't need it
because server code should be compiled native in the first place.

Byte code and .net IL only serve to create the allusion that you can
protect your source code secret source which serves little purpose in
web software. This is why a crappy language like JavaScript is kicking
the static language family buttock.

I gave up Java ten years ago because it was too slow tp create real
client applications and its still a turtle. Why? Byte code.

Merry Christmas.

On Dec 22, 11:50 pm, Charles Oliver Nutter <head...@headius.com>
wrote:
> The JVM is not statically typed.http://blog.headius.com/2008/09/first-taste-of-invokedynamic.html

Dirk Detering

unread,
Dec 26, 2011, 4:01:37 AM12/26/11
to jesse rose, General Dart Discussion

Thanks for the "merry christmas".
But at least my christmas was merrier than yours must have been, writing such mails on 25 dec.

Peter Ahé

unread,
Jan 3, 2012, 3:16:44 PM1/3/12
to Charles Oliver Nutter, General Dart Discussion


On Friday, December 23, 2011, Charles Oliver Nutter <hea...@headius.com> wrote:
> On Dec 23, 2:54 am, "Seldaiendil D. Flourite" <seldaiend...@gmail.com>
> wrote:
>> I thought he was talking about the more extended JVM, after all if you
>> distribute your code it will run on the client VM
>
> OpenJDK has a "tiered" mode now that can start up as fast as client
> and optimize as well as server. It's like to be the standard, if Java
> in the browser ever returns from the grave.
>
> In any case, the failing of JVM developers to recognize and address
> the needs of an in-browser VM have little bearing on whether "bytecode
> VMs" are a good or bad idea.

Actually, it has everything to do with why we don't have a bytecode VM: Focus.

We're not building another Java. We're building Dart, a "programming language for creating structured web applications".

Source code is simple. Bytecodes are an additional complication we don't need.

Sun never really focused on making something that is easy to use. It all got lost in volumes of specifications of things that no developer would ever need, that only other vendors would need.

We make the implementation and our tests available with virtually no strings attached, and specify the things developers actually use. This way we support other vendors even better than Sun or Oracle ever did.

We're interested in supporting other programming languages compiling to Dart, yet there are certain features (threads, most notably) that we don't plan to support. We would not support these things even if we had a specified byte code format.

Byte codes brings nothing to the table but extra complications, some of which Bob and Florian, bless their hearts, tried to illustrate. They have also tried conveying other people's experience and instincts about byte codes. That doesn't mean it isn't possible to make a great byte code VM, it just means that the team behind Dart doesn't think it is.


>
>> As I understand, you are saying JRuby is faster than Ruby. He says JRuby is
>> not as fast as Java because the VM is specialiced for Java.
>
> If that's so, then this is *also* wrong. JRuby with invokedynamic is
> in many cases *as fast* as Java for making calls and walking data
> structures. We do not yet compete on raw numeric performance, but it
> has little to do with the fact that we're targeting a "bytecode
> VM"...it's more the fact that the JVM has always had this non-OO
> crutch of "primitives" to fall back on, and as a result they have not
> until recently spent time optimizing fully-boxed numeric performance.
> A "bytecode VM" designed from the beginning with no primitives and
> with explicit intent to optimize object-based numerics would perform
> very well, as will the JVM once they priorities boxed numeric
> performance (which has already begun due to the popularity and success
> of dynamically-typed languages on the JVM).
>
> Let's not wander too far away from the original post here. I never
> claimed that a Dart-specific VM couldn't run Dart faster than anything
> else. In fact, I made it clear that this would likely be the case,
> since all VMs must choose a feature set to optimize and that feature
> set will not make all the people happy all of the time. I was simply
> countering the FUD that somehow "bytecode VMs" are a bad idea and that
> the JVM and languages built on it show the reasons why. Nothing could
> be further from the truth; if anything, the JVM is a shining example
> of why a "bytecode VM" is an incredibly *good* idea.

We'll just have to disagree on that point. Java has done nothing but make byte codes look bad.

Cheers,
Peter


>
> - Charlie
>

Dominic Hamon

unread,
Jan 3, 2012, 3:31:43 PM1/3/12
to Peter Ahé, Charles Oliver Nutter, General Dart Discussion
On Tue, Jan 3, 2012 at 12:16 PM, Peter Ahé <a...@google.com> wrote:


On Friday, December 23, 2011, Charles Oliver Nutter <hea...@headius.com> wrote:
> On Dec 23, 2:54 am, "Seldaiendil D. Flourite" <seldaiend...@gmail.com>
> wrote:
>> I thought he was talking about the more extended JVM, after all if you
>> distribute your code it will run on the client VM
>
> OpenJDK has a "tiered" mode now that can start up as fast as client
> and optimize as well as server. It's like to be the standard, if Java
> in the browser ever returns from the grave.
>
> In any case, the failing of JVM developers to recognize and address
> the needs of an in-browser VM have little bearing on whether "bytecode
> VMs" are a good or bad idea.

Actually, it has everything to do with why we don't have a bytecode VM: Focus.

We're not building another Java. We're building Dart, a "programming language for creating structured web applications".

Source code is simple. Bytecodes are an additional complication we don't need.

Sun never really focused on making something that is easy to use. It all got lost in volumes of specifications of things that no developer would ever need, that only other vendors would need.

We make the implementation and our tests available with virtually no strings attached, and specify the things developers actually use. This way we support other vendors even better than Sun or Oracle ever did.

We're interested in supporting other programming languages compiling to Dart, yet there are certain features (threads, most notably) that we don't plan to support. We would not support these things even if we had a specified byte code format.

Byte codes brings nothing to the table but extra complications, some of which Bob and Florian, bless their hearts, tried to illustrate.

This is not strictly true. Bytecode has the advantage of being a very efficient representation of the source, which means fewer bytes being sent down the wire. There's also the possibility of an in-memory representation to avoid any performance overhead required to parse the source at the client end.

I'm not arguing against the Dart team decision to use source, just pointing out that it does bring something to the table other than complications.

Peter Ahé

unread,
Jan 3, 2012, 5:26:03 PM1/3/12
to Dominic Hamon, Charles Oliver Nutter, General Dart Discussion

Not in Java:

$ cat > Hello.java
public class Hello {
public static void main(String[] arguments) {
System.out.println("Hello, World!");
}
}
$ javac Hello.java
$ wc -c Hello.java Hello.class
116 Hello.java
417 Hello.class
533 total
$ javac -source 1.4 -target 1.4 -g:none Hello.java
$ wc -c Hello.java Hello.class
116 Hello.java
337 Hello.class
453 total
$ bzip2 Hello.java
$ bzip2 Hello.class
$ wc -c Hello.*
286 Hello.class.bz2
134 Hello.java.bz2
420 total

Here is a dump of the information of the latter version of Hello.class
(the former contains debugging information and stack maps):

Hello.class
Magic number: 0xCAFEBABE
Class file version: 48.0
Constant pool {
#1: void <init>() in java.lang.Object
#2: java.io.PrintStream out in java.lang.System
#3: "Hello, World!"
#4: void println(java.lang.String) in java.io.PrintStream
#5: Hello
#6: java.lang.Object
#7: <init>
#8: ()V
#9: Code
#10: main
#11: ([Ljava/lang/String;)V
#12: void <init>()
#13: java.lang.System
#14: java.io.PrintStream out
#15: Hello, World!
#16: java.io.PrintStream
#17: void println(java.lang.String)
#18: Hello
#19: java/lang/Object
#20: java/lang/System
#21: out
#22: Ljava/io/PrintStream;
#23: java/io/PrintStream
#24: println
#25: (Ljava/lang/String;)V
}
[ACC_PUBLIC, ACC_SUPER] class Hello extends java.lang.Object {
Method: void <init>() [ACC_PUBLIC] {
Code attribute maxStack = 1, maxLocals = 1, codeLength = 5 {
0x0000(00000): 0x2a aload_0
// Load reference from local variable.
0x0001(00001): 0xb7 invokespecial 1 /* void <init>() in
java.lang.Object */
// Invoke instance method; special handling for
superclass, private, and instance initialization method invocations.
0x0004(00004): 0xb1 return
// Return void from method.
Exception table
}
}
Method: void main(java.lang.String[]) [ACC_PUBLIC, ACC_STATIC] {
Code attribute maxStack = 2, maxLocals = 1, codeLength = 9 {
0x0000(00000): 0xb2 getstatic 2 /* java.io.PrintStream out in
java.lang.System */
// Get static field from class.
0x0003(00003): 0x12 ldc 3 /* "Hello, World!" */
// Push item from runtime constant pool.
0x0005(00005): 0xb6 invokevirtual 4 /* void
println(java.lang.String) in java.io.PrintStream */
// Invoke instance method; dispatch based on class.
0x0008(00008): 0xb1 return
// Return void from method.
Exception table
}
}
}

> which means fewer bytes being sent
> down the wire. There's also the possibility of an in-memory representation
> to avoid any performance overhead required to parse the source at the client
> end.

I think you're talking about a "binary representation", not "byte codes" :-)

We are contemplating using a binary representation in some cases. Most
likely, this will be no more than a binary token stream. If this is to
be used for communication between isolates running on different
machines, it will be specified.

>
> I'm not arguing against the Dart team decision to use source, just pointing
> out that it does bring something to the table other than complications.
>

I'm not convinced :-)

Here are some things that Java byte codes doesn't (guarantee) to bring
to the table:

* Names of local variables (temporaries)

* Names of parameters (of methods and constructors)

* Reification of generic types

* Comments

* Annotations

* Debugging information (something as simple as line numbers in stack traces)

* Fast application start up (class data sharing is using
implementation specific format and stil doesn't do enough). FYI:
http://docs.oracle.com/javase/1.5.0/docs/relnotes/features.html#vm_classdatashare

Cheers,
Peter

Reply all
Reply to author
Forward
0 new messages