- WebAssembly was designed with delivery-over-HTTP and browser-based in mind. For that reason, it supports streaming compilation - i.e. you can start compiling the code while downloading.
- WebAssembly was designed to have rapid compilation times (resulting in web pages that load quickly), this is supported by having very simple validation rules compared to Java / JVM languages.
- WebAssembly was designed with the concept of a 'host' environment, i.e. the browser.
- WebAssembly was designed to be secure and simple, minimising the overall attack surface.
- WebAssembly was designed to support a great many languages (C, C++, Rust, ...), whereas the JVM was initially design for a single language, Java.
https://stackoverflow.com/questions/58131892/why-the-jvm-can...
Heh?
> embeds a number of historical mistakes
Well, you need history for that first. Wasm won’t be any different.
> makes sandboxing basically impossible
Why would it? It just turned out that whitelisting should be the default approach to security over blacklisting. There is nothing inherent in the JVM that would preclude one from doing that.
WASM is far, far easier to reason about from a security perspective because its orders of magnitude simpler. There is no standard library. All wasm code (including any library code you compile in to your software) runs in an entirely encapsulated virtual machine with no ability to interact with anything outside of its little bubble. (Except for any functions the application explicitly passes in to the wasm module.) The wasm module boundary is fixed and simple, and as a result its much easier to secure.
I'm sure someone will eventually find a sandbox escape for wasm code somehow. But I bet there'll be at least an order of magnitude fewer sandbox escapes in wasm than we've had with java because of the differences in the security model.
[1] https://www.cvedetails.com/vulnerability-list/vendor_id-93/p...
Also, why would we expose the full filesystem api to a theoretical JVM for the Web? The core of the JVM is a simple stack-machine and a GC, there is nothing demanding all these additional hooks to useful, but potentially unsafe APIs. Of course WASM is safe without any outside functionality, so is brainfuck in and of itself.
So you're suggesting we put a subset of the JVM in the browser, with no access to the java standard library?
Why?
You couldn't run any existing java code or any code in other languages without a compiler. It would just be a weird sub-language that nobody really wants to use, with no existing code or libraries. The pressure would be on to add all the crap from the JRE - putting a tension between security (who knows how secure any of that code is) and usability (who wants a language with no standard library?). This has all played out before and java ended up giving up and deprecating SecurityManager.
Even if you succeed, to what end? So we can run java in the browser? So we have 2 average languages instead of 1? Should we add a C# subset next? The beauty of wasm is that any language can target it.
Or would we compile our C, Go, C# and Rust to this new java subset? But that wouldn't work well - java is missing many features which would be needed to run C code properly. You could make it work using some horrible hacks on top of ByteBuffers, but then it'd run much slower than native code. Much slower than wasm runs today. Whats the point when we could just do the same thing on top of javascript? (And we did - it was called asmjs).
I suggest putting a subset of the JVM that has access to many parts of the standard library, but certain APIs would need proper browser permissions, the same way it works with JS today.
It could run the vast majority of the very high quality of Java ecosystem, and every JVM guest language code out of the box. It is also not a bad compile target -- I would argue that most mainstream languages would actually prefer a managed runtime, and C/C++/Rust are the niche. Aren't there orders of magnitude Java+Python+C#+Haskell+... devs that would prefer to write in their language over JS? Sure, you might say that the reason for WASM's existence is mostly the performance gains for small algorithms, and there certainly is a new niche made available thanks to it, but one way or another people will use it simply due to preferring their stack to JS. The performance aspect is also improved to the JS-only world by possibly allowing proper shared-memory multithreading.
> java is missing many features which would be needed to run C code properly
Why would ByteBuffers be a horrible hack? Is it worse of a hack then what C compilers have to do when targeting WASM, like only having structured control flow? It's just an array read mapped to a single instruction, but in context can also be optimized efficiently (e.g. autovectorizing them when they occur in a loop).
GraalVM actually has support for any LLVM language (though their way of interpretation is different enough from the standard JVM bytecode mode that I only mention it as an interesting data point) with quite great performance, certainly comparable to WASM.
Nonetheless, please don't take my possibly argumentative tone as a negative, I enjoy this discussion and you make great points. I also don't dislike WASM, it is imo a net positive thing. I just believe that a JVM-fueled web failed mostly due to politics, not something inherently technical.
Mmm maybe it is fine in java. I've spent a lot of time benchmarking javascript which has a similar set of primitives (typed arrays). I'm not sure how they perform now, but at the time they were always significantly slower than native javascript arrays for some reason.
> GraalVM actually has support for any LLVM language
Cool - I didn't know that! Thats definitely a point in the direction of the jvm being viable.
> Nonetheless, please don't take my possibly argumentative tone as a negative, I enjoy this discussion and you make great points.
I'm enjoying this too. For what its worth, at a big picture level I think it would definitely be technically possible to do what you're proposing. Its just a question of tradeoffs. Is it easier to tame a subset of java that could usefully fit in the browser, or just start fresh? The downside of starting fresh is that we'd need new compilers and optimizers. And the downside of using java is that the security story is much more complicated, and you'd need to figure out how much of the standard library to bring across and figure out how to secure the FFI.
Obviously the wasm team chose the latter. But perhaps if there were more java fans amongst browser vendors, or the choice was made decades ago, I could easily see the JVM being chosen instead of inventing wasm.
Class loaders, reflection, all methods being virtual, and iteration going through an interface make it much harder to get good performance with the complexity and warm-up time of a JIT.
Type erasure and single polymorphic dispatch makes the JVM's object representation a weird fit some languages.
UTF-16 strings are just awful.
Oracle's business practices rightly scare people away from wanting to build on top of anything they control.
The JVM is a very impressive technology, but it's also almost thirty years old and we've learned a lot since then.
Getting C/C++ code running in the browser was the motivation for Emscripten, and eventually this evolutionary branch gave us WASM (via asm.js).
(and at the time there was plenty of competition: Adobe's Alchemy/Flascc which targeted Flash, and Google's (P)NaCl which compiled to native instructions and later (a subset of) LLVM bitcode, but notably, there was no similar attempt (that I know of) of a C/C++ compiler which targeted the JVM)
There is hardly a more open platform than the JVM, its reference implementation is open source, it has an open specification for both the language and the VM with plenty completely independent implementations, and is so big, running business critical infrastructure in basically almost every FAANG, that any single one would alone pay for its continuous development. Also, Oracle has been a surprisingly good steward of the platform, managing to retain almost the whole Java team from the Sun days (remarkably hard to do that at takeovers), increased the pace of its development and finished open-sourcing everything (formerly OracleJDK had proprietary extensions not found in OpenJDK, nowadays only some trademarked logos remain as the sole difference).
So they mostly own only the name’s trademark, which is no big deal. Remember, google vs oracle happened over Sun’s license that explicitly forbade using their software on mobile devices. No such restrictions exist anymore in case of OpenJDK, which has the same license as the Linux kernel.
They are infamous for reimplementing things worse that were well available decades ago.
And?
No one said that the performance concerns reduce to hardware — but at the Java Applets days it was most definitely the primary reason for their slowness. Since then, with the improvements of JITs, it became very fast.
> than a high-level object-oriented garbage-collected system can muster
That’s not a well-defined performance level and the ceiling changes each year.
And V8 has no real parallelism, so for many kind of workloads they are not drop-in replacements.
What happened is that people realized that blacklisting does not work. Whitelisting is the correct approach. There is absolutely zero reason why WASM would be better for that over the JVM — the JVM spec in itself has no visible side effect, not even printing, so it can’t do anything nefarious (besides cpu vulnerabilities, but that also apply to WASM).
And you would run C code in a completely trivial way: you have a huge array which is your memory, and you read/write bytes to it.
> And you would run C code in a completely trivial way: you have a huge array which is your memory, and you read/write bytes to it. That sounds like it would have terrible performance. Would every read of an int have to manually build it from the 4 bytes it's made of? This just seems like something the JVM won't handle that well.
Besides, this would mean that if you want to run a language like C#, which has references and value types (and you can make a reference to a value type from a pointer into a buffer), you would have to emulate them, which will hamper performance, or just use the same strategy as you used for C.
No, a method can have a native implementation, or a compiler intrinsic. Java has ByteBuffers (https://download.java.net/java/early_access/panama/docs/api/... ), and they have put/get{Long,Short,etc}, that will map to either a native single pointer read with the given size, or even optimize to a more efficient read inside the context of a bigger method, say vectorize them inside a loop (as the compiler knows about this method and can handle it specifically).
> Besides, this would mean that if you want to run a language like C#, which has references and value types (and you can make a reference to a value type from a pointer into a buffer), you would have to emulate them, which will hamper performance, or just use the same strategy as you used for C
So we are back at where WASM is? Though I think that there is nothing inherently impossible about mapping C# to more efficient Java primitives, especially that value types are the more constrained semantics, each instance being different is semantically the same, just less optimal. A pointer to a region of the aforementioned ByteBuffer with a special memoryToCSharpObject() that has some compiler intrinsics wouldn't perform too bad, I believe.
Exactly. By the time you've done all that, whats the point? You'll have reimplemented wasm on top of the jvm in a way that:
- Can't use any of the java standard library (which all existing java code depends on)
- So you also can't use any existing java code
- You need a compilation step for any existing code in other languages to convert it into your special limited java syntax
- And the result will run slower than wasm because of the extra layer of abstraction going on
The one advantage is that you can output everything as standard .class files, so it'll be easier to pull this code into an existing java application.
And yes, you could absolutely do that if you want and you see value in it. Heck - maybe it'd be nice to have a wasm-to-java-class converter to let you reuse all the wasm infrastructure.
But this all sounds like the java equivalent to asmjs, which we already tried. Asmjs was the precursor to wasm. It was built on top of javascript primitives in much the same way as the proposal here builds on top of java primitives. As I understand it, the reason we ended up with wasm instead of asmjs was that:
- Wasm was easier to optimize, had a smaller file size and was faster to load at runtime (since you don't need a javascript compiler)
- Its much easier to make VMs for wasm in lots of languages and environments. Wasm modules can be loaded into programs written in python, rust, C, java, go, javascript, etc without some weird unnecessary dependency on javascript.
One can surely cherry-pick quite a lot out of it that are safe to use, e.g. anything not using `native` implementation can as per the former definition of JVM interpreter, also end up being safe. So many existing code would run without any change.
> Re: compilation step
Why? It has nothing to do with Java, the language, only the JVM class file format. Scala/Kotlin produce bytecode directly, not Java code.
> Run slower
Why would it? Wasm can run fast having grown out from asm.js, yet a JITted runtime that runs half of the internet can't?
> Its much easier to make VMs for wasm in lots of languages and environments
There are plenty toy JVMs out there as well, the core really is not difficult.
And the point of all this would be that large chunks of the JVM could have been reused, that runs on every platform with top notch performance already, without all the growing pains that WASM will experience. Also, the JVM's type safe cross-language capabilities are already here, while they are very experimental and rudimentary in case of WASM. I can just call a Kotlin class from Clojure, or JPython or whatever, and vice versa.
Java already tried - many times - to have a "safe subset" of the language. As I understand it, the effort was finally abandoned with the deprecation of SecurityManager. But even if you made a safe subset of java, you've only gone from 1 working browser language (javascript) to 2 (javascript and java). Well, and the compile-to-JS & compile-to-JVM languages.
> Also, the JVM's type safe cross-language capabilities are already here
But that leaves out a lot of languages that people care about. Important languages, like C, C++ and Rust, C#, Go and Python. These languages don't compile to the JVM because of limitations in the java bytecode format and type system.
I mean, how would you make C or Go run on the JVM?
Perhaps java's type system could be extended to support these languages too. But it would probably take 20 years of committee meetings to do it. And the time to start that work was 20 years ago. At this point its much easier to start fresh with something new like wasm.
[Edit: In another thread you mentioned graalvm has been made to support any LLVM code. Thats great, and perhaps addresses this point entirely. I don't know enough about it to know.]
> Why would it [run slower]? Wasm can run fast having grown out from asm.js, yet a JITted runtime that runs half of the internet can't?
The challenge is making existing C code run at near-native speeds. How would you do that with your proposal? You'd need to first compile your C to java classes and then ran the code in the JVM. But java has no native pointers or direct access to an allocator. Java's GC alone would incur a massive performance penalty to C code.
Asmjs was made fast by making javascript engines contain a second, separate compiler for the asmjs dialect. The compiler detected asmjs explicitly and essentially used asmjs as a weird, expensive syntax for a different language. I guess java could do that too. We could have a special .class file syntax subset and add special compiler logic to the jvm to optimize that particular dialect. But if you're going to go down that road, why bother with the JVM? Javascript is already in the browser. For that matter, why not just compile your java classes to javascript?
> There are plenty toy JVMs out there as well, the core really is not difficult.
I'm confused - are you proposing just porting across the core of java, or java with a lot of its standard library? Given the size of the JRE, those are two very different propositions! The former is possible but pretty useless, and the latter is a massive job that the java community has already tried and as I understand it, eventually given up on.
> Also, the JVM's type safe cross-language capabilities are already here,
Oh no, this keeps getting worse. You want to put java's FFI system in browsers too?
The problem with Java's various FFIs is that (AFAIK) they're not designed to be a security boundary. We'd need to redesign them all. The surface area is massive and given java's historically abysmal security record, I don't trust the java engineers to make any of this stuff safe or secure. And neither should you.
No, it sounds like you want to bring most of the JVM into the browser to solve a problem I don't have (run existing java code in the browser). And this still doesn't address the problem that wasm solves (let us run any language in the browser, safely and without a loss in performance). And I can't see any straightforward way to address the security problems or the performance problems that this would entail.
In comparison, I'm much happier with the design of wasm. By making a small, simple new bytecode format which explicitly supports C and C-like languages, all wasm languages run fast by default. Wasm is dead easy to sandbox and easy to audit. And this gives us the best of both worlds, since we should be able to compile Java to wasm like any other language. Better yet - this way you can bring in as much of the JVM as you want into your projects, and there's no need to do the solve the impossible problem of making the JVM secure.