I know it's a pedantic point, but one I stand by...that there's literally nothing Java can do that C cannot because C can write Java!
I don't go around saying C is faster than Java. I just say Java cannot be faster than C.
When talking about performance you say that “there's literally nothing Java can do that C cannot because C can write Java” but other than the tautology that they are both Turing machines, your conclusion doesn’t follow.
The Java runtime dynamically optimises based on the currently executing code, but C compiles to static CPU instructions. A C program is statically optimised so it’s possible that some optimisations in C will perform worse than those in Java because Java knows more about the actual code paths taken at runtime, and this can change between executions.
For C to be able to optimise itself the same way that Java does, it would need its own heavyweight runtime and bytecode, like Java does (as I think you suggest). But C doesn’t actually have such a runtime, and although I’m certainly no expert on the C language spec, I assume it has all sorts of runtime guarantees and a memory model that would preclude arbitrarily rearranging the executable code at runtime, so it arguable that the resulting system wouldn’t actually be “C” if it did this.
Put another way: although Java is/was written in C, the way Java works is fundamentally different to C, and because of this, certain optimisations are available to Java that are not available to C.
(All of that said, in my experience C code is always faster than Java code, these days I use Go and Swift, and I’m very happy to have seen the back of the JVM.)
So, consider a perfectly spherical Java language… :)
----
Also, by the same argument you're using, git should be faster if written in assembly; since assembly can do more than C can.
The tradeoff between performance and easiness to write the program has already been made by writing git in C. The only difference in using Java is a different point in that tradeoff.
I'd also contend that Java gives you much more bang for the buck in that tradeoff than C. Java is stupidly easy to write, especially if you want to do multithreading. With C you'd have to start writing some form of primitive GC, or have the disciplined paranoia of Rust's borrow checker yourself.
You could maybe write some kind of translator in C to emit JVM bytecode, and have it recompile itself at runtime. The problem with that line is that it is a lot of work and then to be fair we should allow a similar effort to be applied to a JVM like HotSpot for an apples-to-apples comparison.
Then remember the original thesis, which is that we claimed Java was only faster for specific usecases. That is a very wiggly claim that I bet could nearly always be found true.
Anyway, fun to think about either way.