Next: , Previous: Full Calls, Up: Calling Convention

2.4 Unknown-Values Returns

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.