Next: IR2 Conversion, Previous: Full Calls, Up: Calling Convention
The unknown-values return convention consists of two parts. The
first part is that of returning a single value. The second is
that of returning a different number of values. We also changed
the convention here recently, so we should describe both the old
and new versions. The three interesting VOPs here are return-single
,
return
, and return-multiple
.
For a single-value return, we load the return value in the first
argument-passing register (A0
, or EDI
), reload the old frame
pointer, burn the stack frame, and return. The old convention
was to increment the return address by two before returning,
typically via a JMP
, which was guaranteed to screw up branch-
prediction hardware. The new convention is to return with the
carry flag clear.
For a multiple-value return, we pass the first three values in
the argument-passing registers, and the remainder on the stack.
ECX
contains the total number of values as a fixnum, EBX
points
to where the callee frame was, EBP
has been restored to point to
the caller frame, and the first of the values on the stack (the
fourth overall) is at [EBP-16]
. The old convention was just to
jump to the return address at this point. The newer one has us
setting the carry flag first.
The code at the call site for accepting some number of unknown-
values is fairly well boilerplated. If we are expecting zero or
one values, then we need to reset the stack pointer if we are in
a multiple-value return. In the old convention we just encoded a
MOV ESP, EBX
instruction, which neatly fit in the two byte gap
that was skipped by a single-value return. In the new convention
we have to explicitly check the carry flag with a conditional
jump around the MOV ESP, EBX
instruction. When expecting more
than one value, we need to arrange to set up default values when
a single-value return happens, so we encode a jump around a
stub of code which fakes up the register use convention of a
multiple-value return. Again, in the old convention this was a
two-byte unconditionl jump, and in the new convention this is
a conditional jump based on the carry flag.