Up to this point, we've left the exact mechanics of parameter passing underspecified, because generally we only care about the high-level semantics and want to leave the details up to the compiler to present value semantics in an efficient way. Concretely, for small values of concrete type (up to 3 machine registers in size) we pass and return those values in registers, and for larger values, or values of generic type, we pass them indirectly by pointer. Depending on the situation, the callee may "borrow" an immutable representation of the value, which can be shared between the caller and callee without making a copy, or the callee may "take" its own copy of the value, which it can move into place somewhere else; we generally use the "borrow" convention except in setters and initializers, since those two are the most likely places where we're likely to want to use an argument to form part of another value.
We're fleshing out more details of the parameter passing model, and providing user controls for it, in this feature pitch: