仰る通り、関数呼び出しのオーバーヘッドは結構重くてタイトなループの内部では特に問題になります。
クラス内のメソッドはメンバ変数にしか触れないように言語を設計することは可能ですが、その場合に外部から値をどうしても渡す必要がある場合は外部からメンバ変数に向けてsetterのような形で値をねじ込む形になるでしょうか。それはおよそスタックで情報を出し入れしてる時とコスト的にほぼ同じかCPUサポートがない分やや遅いかも知れません。
わざわざ状態をスタックに複製しているコードから結果を変えずにスタックを使わないように書き換える事は常にできるとは限りません。C++であれば関数の後に__attribute__((always_inline))
と付ける事でインライン化を強制できますし出来なかった場合にはコンパイルエラーになるのでどういうケースでスタックが不可欠かわかると思います。またインライン化は同一のコードがそこら中に埋め込まれる事になるのでコードサイズを肥大化させます。
インライン化の他だと末尾再帰最適化なんてのは関数を潰せる典型的な例で「関数の最後での関数の呼び出しなら今のスタックフレーム内のローカル変数は同じ領域を使いまわしてしまえ」という事でgoto相当のループを行う機械語を吐き出す事で関数を呼び出さずに実行を高速化できます。これは結構教科書的に恩恵がわかりやすい最適化ではあるのですが、世の中のコンパイラ製作者達は他にも関数呼び出しを端折る方法を常に血眼になって探しています。
そういえばAndroidやiPhoneで使われているARM系CPUは命令セットの中に「関数呼び出し」に相当する物が無く、代わりにすべてレジスタのコピーとジャンプ命令で関数と同等の機能を実現しています。その実行パス上で複製する必要がない事が静的に確定できる場合において複製操作自体を消去する、というのは通常の最適化の範疇の中ですでに行われている気がしてきました。