Correct me if I'm wrong, but aren't you confusing Java the language with the actual JVM? On your last paragraph, you pretty much described what the JVM is in my perspective.
There is no proper separation of concerns in the JVM. The JVM instruction set has instructions like `invokevirtual` and `invokestatic`, `invokeinterface`, which are Java specific features. The JVM also knows the concept of classes and methods and fields, even though those abstractions should be defined at the language level, not at the VM level (a Lisp or Forth-like stack machine needs different abstractions).
The datatypes in the JVM are pretty weird. You have chars, but not unsigned chars, some integer types (but not all). You have no support for unicode. There is a low-level struct for arrays and multidimensional arrays (of a specific type), but for nothing else. It supports exceptions, but only Java like exceptions. (You can't make an exception system where execution can be retried or resumed; it's just not supported). It also has a java-specific thread model (want to create lightweight threads with lockfree data structures? nope, not gonna work).
What you want is a low-level platform with different modules that can be picked by the people who implement the programming language. Pick a parser module, a garbage collection module, a JIT compilation module, and so forth. This is really difficult, because you have to have a good understanding what kind of primitives different programming languages need. When all these things are fixed and non-interchangeable you end up with a virtual machine that is suitable only for a specific kind of language. It's turing complete, so of course you can make any language on the JVM, but it's just not a good fit.
The datatypes in the JVM are pretty weird. You have chars, but not unsigned chars, some integer types (but not all). You have no support for unicode. There is a low-level struct for arrays and multidimensional arrays (of a specific type), but for nothing else. It supports exceptions, but only Java like exceptions. (You can't make an exception system where execution can be retried or resumed; it's just not supported). It also has a java-specific thread model (want to create lightweight threads with lockfree data structures? nope, not gonna work).
What you want is a low-level platform with different modules that can be picked by the people who implement the programming language. Pick a parser module, a garbage collection module, a JIT compilation module, and so forth. This is really difficult, because you have to have a good understanding what kind of primitives different programming languages need. When all these things are fixed and non-interchangeable you end up with a virtual machine that is suitable only for a specific kind of language. It's turing complete, so of course you can make any language on the JVM, but it's just not a good fit.