7.8.函数实现前瞻

\(7.8.\)Function Impletation Preview

1.Program execution

  • When a function enters its execution, we need to create a state for this function.

    • Give it an empty working stack, its memory segment.
  • The working stack and some of the segments should be:

    • Created when the function starts running.
    • Maintained as long as the function is executing.
    • Recycled when the function retums.
  • When we call a function, we will have two states: the state of caller and the state of callee. Once the callee starts running, the state of the caller has to be saved somewhere. And when the callee terminates, we can reinstate the caller state and continue its execution.

2.Function call and return

  However, a calling chain may be several functions deep, and how can we maintain all the states of these functions?

  To deal with this, we can use the FILO (first in last out) pattern. The only function to be return is the function which is currently running, and which is also the end of the calling chain. Once this function returns, the calling chain shortens, so on and so forth.

  This pattern is similiar to stack, this implies that we may use a stack in order to save and retrieve all these function states.

  Take this simple function as example:

1
mult(17, 212)

  In the view of the caller, the effect of the procedure is that the function's arguements has been replaced with the function value:

 And the details are as follows:

  • We push some values in the stack, and nothing happens. And then we call foo nArgs.

  • By the information nArgs, we know where to set arg pointer.

    • From now on, we know what's above the arg is the working stack of the caller, and what's below the arg are the arguments to be use by callee.
  • Before we jump to the called function, we have to save the state of the caller:

    • The working stack is safe, it is already on the stack, so we can leave it alone.
    • We have to save the segment and the return address. Taken together, we call these thing frame.
    • The VM implementation simply push these memory segments into stack. In this way we save the frame, and will be able to return to them later on.

  • Jump to execute foo.

  After the called function is entered, it:

  • Create a local segment.

  • Having known that we need n variables, we need to initialize them to 0

    • From now on, we can refer to these values as local 0, local 1 and so on.

  Assume that the called function is running and doing its things, in this process, it:

  • Grow its working stack, and it now has a working stack of its own.

  • When it is goint to return at some point, we push the return value at the bottom of the stack.

  • We pop the topmost value, and copy it onto argument 0 to replace the pushed arguments with return value.

  • We restore the segment pointers of the callers, take the saved memory segments to the current segments.

  • Then we clear the stack of the called function, and set the stack pointer for the caller.

    • The stack pointer should be located after argument 0.
  • Finally, we jump to the return address in the caller, and continue executing the caller's code.

3.Global stack

  Our previous discussion is only about the caller and callee, but there are many other pairs of callers and callees in the calling chain, and we have to maintain their states, too.

  As a result, we get a very large stack called global stack containing the information of the entire program.

  • We refer to some subset of the global stack block. It's the world of the currently running function, and it contains:

    • argument segment. These are the function's arguments.
    • saved information that belongs to caller.
    • local segment
    • working stack of its own

  • The global stack contains many more such blocks.

  And there are some more observations we can make:

  • We only have to save local, argument, this and that segments, for the other four parts don't belong to the world of the function.
  • We use the stack not only when executing the program, but also executing all the behind-scene apparatus that is required to service the program. Everything is saved on the same stack.