Thursday 6 August 2015

Returning from a function

I remember the first time I saw someone violate the return conventions in a function.

This was in submission to Personal Computer World magazine.  They used to run a column where people could write in with their own utility routines.

Someone submitted a routine that returned the current contents of the program counter - that is to say where in the code you are currently executing.

The routine looked like this:

; v.1
WHEREAMI  POP  HL
          PUSH HL
          RET

Perfectly simple; you pop the return address into the HL pair then push it back on the stack and then return as normal.  You might use it like this:

...
76C9      CALL  WHEREAMI
76CC      ; on return, HL contains 76CC
...

The author submitted comprehensive documentation about the routine, aiming at some arcane humour in setting a new record for comment-to-code line count ratio.

However the record was promptly snatched away by the editor of the column, who pointed out that the routine can be rewritten thus:

; v.2
WHEREAMI  POP  HL
          JP   (HL)

You can hear the original author saying damn.  Or can you?  There is more than just a simple optimisation that separates v.2 from v.1 - in fact a different way of thinking is at work.  I would have written v.1.  I know about the JP (HL) instruction but until I saw this I would never have thought of v.2.

I pondered for a long time before I was convinced that v.2 would really work.  It looks like one of those dodgy bodges that looks good but falls over when you apply it to the real world.  Surely what happens when the routine that calls WHEREAMI returns to whereever it came from?  No that would work.

It's just so... disturbing... to see someone ending a function with a jump rather than a return, much as it would be to see someone leave a meeting by leaping out of the window rather than walking through the door.

In v.1 we temporarily allow ourselves to peek at the stack, and make a strict point of putting it all back where it was before we proceed.  It is not our business to mess with the stack.  It is not our business to tell the processor where to go next.  That is all taken care of automatically by CALL and RET and we do poke around there unless we want to lose a finger in the machinery.

In v.2 the attitute is different.  We take responsibility for the flow of control, we grab the return address and use it ourselves - this is a significantly different way to think about code.

No comments:

Post a Comment