> Your CPU doesn’t know or care what functions are
This has already been commented on by a couple of people, but yes, your CPU absolutely does care a lot about functions. At the very least, call/ret matching is important for branch prediction, but the big arches nowadays have shadow stacks and CFI checks that require you to use call/rets as regular functions. x86 has a more thoroughly built-in notion of functions, since they have a (since mostly-defunct) infrastructure for doing task switching via regular-ish call instructions.
> The toString method that gets called depends on the type of the receiver object. This isn’t determined at compile time, but instead a lookup that happens at runtime. The compiler effectively generates a switch statement that looks at the result of getClass and then calls the right method. It’s smarter than that for performance I’m sure, but conceptually that’s what it’s doing.
No, it's conceptually doing the exact opposite. Class objects have a vtable pointer, a pointer to a list of functions, and the compiler is reading the vtable and calling the n'th function via function pointer. The difference is quite important: vtables are an inherently open system (anyone can define their own vtable, if they're sufficiently crazy), but switches are inherently closed (the complete set of possible targets has to be known at compile-time). Not that I've written it up anywhere, but I've come to think of the closed nature of switch statements as fundamentally anathema to the ideals of object-oriented programming.
The vtable vs switch dichotomy was called the “expression problem” by Philip Wadler https://en.wikipedia.org/wiki/Expression_problem