There is a cost: subroutine calls get wrapped in something called a trampoline, and some data is duplicated across multiple banks. You would do both of these things in assembly language too, and could even do it more optimally, but it's an NP-hard problem and takes a lot of thinking.