Tracing JITs should be able to spit out, as they run, the tables of Bayesian confidences they've built up for various static properties of the code, which can sit along with things like source maps, and be confirmed/rejected by the programmer in their IDE, or just live-reloaded into a new VM ala a Smalltalk image. (Future-tech, remember.) You can see the potential for this in things like Erlang's typer+dialyzer system.
Likewise, static analysis tools should be able to work on foreign code after transpilation. There's nothing stopping you from transforming C code into Rust code in order to get the Rust compiler's opinion on its ownership semantics.
Note that I'm not saying that there's one universal underlying language semantics. Just that language semantics (which consist of such things as a type system, a threading/memory model, etc.) have no reason to be tied to either a particular syntax, or a particular VM. (Effectively, a language semantics forms an abstract machine that executes more or less efficiently on the substrate of any given VM. MRI Ruby is a direct substrate for Ruby semantics; IronRuby is less-clear substrate; etc.)
> those may significantly affect the suitability of an algorithm for a certain language
This is a problem of transparent distribution. I've been working on an Elixir DSL for writing Haskell "inside" Elixir for efficiency. The result is not a Haskell compiled module getting linked into the Erlang VM, but rather a separate Erlang-VM-managed Haskell "application server" being run as a port program. I foresee much more of this, and much more cleverness about it: writing code that compiles to a bunch of separate modules for separate VMs, which then form a micro-distributed-system all within a Docker container or somesuch.
Again, it's not about eliminating the plurality of runtimes—it's about rendering that plurality moot, abstracting it away from the perspective of the programmer and leaving it up to the implementation to decide how to optimize abstract-machine-to-VM allocation.
There's no reason that you can't have every language semantics available to any library, to use in any combination (this parameterized type system with that green-threading and this other GC, etc.) It's just that, in so doing, you're either transparently importing into your single runtime some virtualization layers for all the other abstract machines you've coded in terms of (somewhat like writing a Windows app on Linux by linking it to Wine), or you've let the Sufficiently Smart Code-generator go beyond the premise of having a single target platform.