Next: , Previous: , Up: machinery   [Index]


16.6 Scheme stack overflow

Let’s recall how the Scheme stack segment looks, machinery stack overflow. Function call frames are put on the stack starting from high memory addresses, stack usage grows towards low memory addresses; at some point the stack runs out of space.

      high memory
|                      |
|----------------------|
|                      | <- pcb->frame_base
|----------------------|                        --
| ik_underflow_handler |                        .
|----------------------|                        .
           .                                    .
           .                                    .
           .                                    .
|----------------------|                        .
|                      | <- pcb->frame_redline  . stack
|----------------------|                        . segment
           .                                    . size
           .                                    .
           .                                    .
|----------------------|                        .
|                      | <- pcb->stack_base     .
|----------------------|                        --
|                      |
       low memory

Figure 16.49: Stack boundaries as represented by the PCB.

To detect stack usage approaching the end of available stack space: the PCB contains a field referencing a machine word 2 memory chunks (4096 bytes each) above the lower boundary; whenever stack usage crosses this “red line”: a new stack segment needs to be allocated and call frames must be put on the new stack; machinery stack overflow.

      high memory
|                      | <- pcb->frame_base
|----------------------|
| ik_underflow_handler |
|----------------------|
           .
           .
           .
|----------------------|                        --
|     local value      |                        .
|----------------------|                        .
|     local value      | <- pcb->frame_redline  .
|----------------------|                        . framesize
|     local value      |                        .
|----------------------|                        .
|    return address    | <- FPR                 .
|----------------------|                        --
|   function argument  |
|----------------------|
|   function argument  |
|----------------------|
           .
           .
           .
|----------------------|
|                      | <- pcb->stack_base
|----------------------|
|                      |
      low memory

Figure 16.50: Scenario on the Scheme stack that triggers the stack overflow; we see that: FPR < pcb->frame_redline.

Scheme functions can be partitioned in: those that may use more stack space, those that do not; Vicare recognises this partition and inserts a stack overflow check at the beginning of each of the former. The pseudo–Assembly performing the check is as follows:

(label function_entry_point)
  (cmpl FPR pcb->frame_redline)
  (jb L0)

(label L1)
  ... the function body ...
  (ret)

(label L0)
  (forcall "ik_stack_overflow")
  (jmp L1)

When stack overflow happens the C function ik_stack_overflow() is called through the forcall primitive instruction and the Assembly subroutine ik_foreign_call; forcall creates a new stack frame and then calls ik_foreign_call which in turn calls the C function, machinery stack overflow.

      high memory
|                      |
|----------------------|                        --
|     local value      |                        .
|----------------------|                        .
|     local value      | <- pcb->frame_redline  .
|----------------------|                        . framesize
|     local value      |                        .
|----------------------|                        .
|    return address    |                        .
|----------------------|                        --
|   function argument  |                        .
|----------------------|                        . frame of
|   function argument  |                        . forcall
|----------------------|                        .
|    return address    | <- FPR                 .
|----------------------|                        --
|                      |
      low memory

Figure 16.51: Call frame of forcall on top of the call frame that caused the stack underflow.

ik_stack_overflow() does the following:

  1. Freeze all the call frames on the stack in a continuation object; prepend such object to the list of continuations in the PCB, so that it becomes the “next PCB continuation”.
  2. Allocate and initialise a new stack segment and register it in the PCB. The frame pointer is set to reference the first machine word on the stack, which contains the address of the underflow handler.
  3. For garbage collection purposes: reconfigure old stack segment’s memory block as data segment.

Upon returning to the caller ik_foreign_call performs a ret Assembly instruction with the FPR referencing the underflow handler; so returning from a stack reallocation is exactly like returning to the next PCB continuation.


Next: , Previous: , Up: machinery   [Index]