Although that's true (ish... you can run WASM on the JVM now, and also LLVM bitcode), that takes you into the realm of why you'd want to.
On the browser side, you could maybe make a ChromeOS style argument of just wanting to run everything in a browser no matter what, it's nice for it to be sandboxed etc. But if you look at what your Postgres is doing it's sort of a Linux VM, and you can run those already at full speed: that's WSL and there are various solutions on macOS like Docker Desktop.
On the server side, the reason nobody bothered trying to run Postgres on the JVM before Graal is that it's unclear what the benefit is. Security? Processes and kernel isolation seems to work well enough on the server, and anyway Postgres is a highly trusted component anyway. CPU independence? That hasn't been useful since stuff like SPARC died, we are now just starting to see ARM chips appear on the server, but compiling native code for both intel and arm isn't hard and Linux distros have the infrastructure to do it for a long time already. For custom servers, well, not many are writing them in C/C++/Rust anyway these days. RISC-V remains mostly theoretical.
To what extent is this doing it because it can be done, vs delivering real benefits? My mind is open but the low level nature of the WASM instruction set also means the VM can't offer many benefits to the programs inside it, nor the users outside it.
The JVM has historically and famously sucked at sandboxing untrusted/partially trusted code. The JVM also isn’t a suitable compilation target for arbitrary and existing codebases.
WASM is built to sandbox untrusted/partially trusted code. WASM is built as a compilation target rather than a complete hosted VM with bells and whistles.
There are advantages and disadvantages to this. One advantage is language-agnosticism. Another might be around the ability to run user-supplied untrusted code in a much safer way. See Cloudflare functions.
One disadvantage is the lack of bells and whistles.
So, the answer to “why is this different to the JVM” is that.
"The JVM has historically and famously sucked at sandboxing untrusted/partially trusted code. The JVM also isn’t a suitable compilation target for arbitrary and existing codebases."
We need to drill into this a bit more, because the WASM ecosystem can certainly learn lessons and do better than the JVM but this isn't quite the right set of lessons to learn.
The JVM spec was written from day one to sandbox arbitrary and partially trusted code. The SecurityManager architecture is now being removed, but that's a big project exactly because it was deeply integrated into everything. It's also embeddable and a compilation target (it interprets bytecode), and later it was extended with features designed to make it more language agnostic as well at least for everything at the same level of dynamism of Java or higher (so indeed not C/C++ but yes for most other langs).
So the interesting thing to debate here is not really the design goals, which are very similar, but what concretely will make WASM more successful at achieving these goals.
For example, what made the SecurityManager difficult wasn't something fundamental to the JVM but rather that code which is both useful and sandboxed needs APIs that let it do privileged things in controlled ways, and a lot of the bugs were in those API implementations or on the boundaries. That's especially the case on the desktop where sandboxed code had to call into a lot of OS libraries.
On the web this problem is solved with the browser makers exposing JS/renderers to WASM or just saying do the tricky stuff in JS, and then wrapping the whole thing with kernel sandboxes and IPC to handle the fact that the JS/WASM sandbox itself will inevitably fail in the same way. In other contexts this, well, doesn't seem to be solved, really? The moment you start exposing APIs to the WASM code you face the same problem. Also these days you have spectre to think about, so maybe you need a separate process sandbox anyway. Alternatively you can do what the GraalVM guys are doing (in their EE) and using Intel MPKs but that's pretty advanced and I didn't hear about anyone else doing that.
Now there are still some crucial differences! The JVM wanted to allow sandboxed code to interop smoothly with higher privileged code. This opened up a bunch of reflection-based bugs whereby you could reflect your way to the SecurityManager and switch it off, confused deputy attacks and so on. There's no equivalent in WASM, but that's partly because (current?) WASM doesn't really try to define a fine grained permissions model or a way to mark some bits of code in a program as more privileged than others. It also doesn't provide a large set of pre-implemented APIs. The sandbox is whatever the developer exposes to the context. This doesn't make WASM stronger, it just means it punts the really hard bits to the user i.e. browser devs. GraalVM's new JVM sandbox (not SecurityManager based) works mostly the same way, as do process sandboxes so this is definitely the trend, but of course there was a reason the SecurityManager was created that way and it's because it requires way more code and work by the developer to sandbox code if you don't have support for tight mixing. So maybe the sandboxes that do exist will be stronger, but there'll be less sandboxing overall and permission scopes will be much wider. Is that the right tradeoff? I'm not totally sure it is but eh, people really like all-or-nothing and that's the way the industry is heading now.
At any rate that discussion is a bit academic, because you can't do an OOP capabilities type architecture in C anyway.
What about language agnosticism? Again the hard part here isn't having a common bytecode - CPUs already provide that - it's all the engine bindings and semantic alignment required. If you want to pass a std::time into JavaScript then something has to bridge that gap, if you want to call into a dynamically typed language from a statically typed language, then something has to generate interfaces for the compiler to check against and so on. Here I don't see what WASM has to do with anything really, it's just not in scope. Compiling a Python interpreter to WASM doesn't make it any easier to call Python from C++, or Java, or JavaScript. The SOTA there is Truffle/JVM by far.
Wasm composes in the way that the JVM/SecurityManager did not. You can implement your proxy functions in wasm, not only defining the set of functions that a Wasm program uses to talk to the outside world, those proxy functions that you pass in can also be implemented in wasm inside of another context.
Wasm can learn from the JVM for sure, but if you went almost 30 years back in time, you would have some great tricks to teach the JVM, learned from Wasm.
I don’t really have much else to add to this discussion right now (it would require too much brain power whilst sitting next to a fire), but I would like to thank you for this very detailed and informative comment.
On the browser side, you could maybe make a ChromeOS style argument of just wanting to run everything in a browser no matter what, it's nice for it to be sandboxed etc. But if you look at what your Postgres is doing it's sort of a Linux VM, and you can run those already at full speed: that's WSL and there are various solutions on macOS like Docker Desktop.
On the server side, the reason nobody bothered trying to run Postgres on the JVM before Graal is that it's unclear what the benefit is. Security? Processes and kernel isolation seems to work well enough on the server, and anyway Postgres is a highly trusted component anyway. CPU independence? That hasn't been useful since stuff like SPARC died, we are now just starting to see ARM chips appear on the server, but compiling native code for both intel and arm isn't hard and Linux distros have the infrastructure to do it for a long time already. For custom servers, well, not many are writing them in C/C++/Rust anyway these days. RISC-V remains mostly theoretical.
To what extent is this doing it because it can be done, vs delivering real benefits? My mind is open but the low level nature of the WASM instruction set also means the VM can't offer many benefits to the programs inside it, nor the users outside it.