Also implicit in message passing is a form of structural typing; objects that understand the same set of messages (called a protocol in Smalltalk-speak) are type-equivalent. A client class may delegate to any object that understands the messages the client sends to its delegate. One of the advantages this brings is all the crazy things you can do with #become: in Smalltalk. A perfectly valid way of responding to a message you haven't implemented is to construct an instance of a class that has an implementation for that message, and then become: that instance, swapping all references to yourself in system memory with a reference to the instance you created before passing the message onto the instance (your new self). There's no way to implement general #become: in C++ or Java because there's no guarantee the result will be sound type-wise.
The changes are subtle but they open up a world of dynamism that Java programmers don't have access to. Which is fine for Java programmers, who decided they don't want that kind of dynamism anyway, but there are programmers who work better shaping a live system rather than declaring type ontologies in advance. And Smalltalk is designed to work well with such programmers.
Are you telling me that if I turn on a compiler optimisation my message passing program suddenly becomes a method call system?
So the difference cannot be what it compiles to.