Introduction: One problem with the access-link approach to nonlocal data is that if the nesting depth gets large, it may have to follow long chains of links to reach the data we need. A more efficient implementation uses an auxiliary array d, called the display, which consists of one pointer for each nesting depth. It arrange as, at all times, d[i] is a pointer to the highest activation record on the stack for any procedure at nesting depth i. Examples of a display are shown in Fig. 7.14.
For instance, in Fig. 7.14(d), we see the display d, with d[l] holding a pointer to the activation record for sort, the highest (and only) activation record for a function at nesting depth 1. Also, d holds a pointer to the activation record for exchange, the highest record at depth 2, and d points to partition, the highest record at depth 3.
The advantage of using a display is that if procedure p is executing, and it needs to access element x belonging to some procedure q, we need to look only in d[i], where i is the nesting depth of q; we follow the pointer d[i] to the activation record for q, wherein x is found at a known offset. The compiler knows what i is, so it can generate code to access x using d[i] and the offset of x from the top of the activation record for q. Thus, the code never needs to follow a long chain of access links.
In order to maintain the display correctly, we need to save previous values of display entries in new activation records. If procedure p at depth np is called, and its activation record is not the first on the stack for a procedure at depth np, then the activation record for p needs to hold the previous value of d[np], while d[np] itself is set to point to this activation of p. When p returns, and its activation record is removed from the stack, we restore d[np] to have its value prior to the call of p.
Example: Several steps of manipulating the display are illustrated in Fig. 7.14. In Fig. 7.14(a), sort at depth 1 has called quicksort (l, 9) at depth 2. The activation record for quicksort has a place to store the old value of d, indicated as saved d, although in this case since there was no prior activation record at depth 2, this pointer is null.
In Fig. 7.14(b), quicksort (l, 9) calls quicksort (l, 3). Since the activation records for both calls are at depth 2, we must store the pointer to quicksort (l, 9), which was in d, in the record for quicksort(l, 3). Then, d is made to point to quicksort(l, 3).
Next, partition is called. This function is at depth 3, so we use the slot d in the display for the first time, and make it point to the activation record for partition. The record for partition has a slot for a former value of d, but in this case there is none, so the pointer remains null. The display and stack at this time are shown in Fig. 7.14(c).
Then, partition calls exchange. That function is at depth 2, so its activation record stores the old pointer d, which goes to the activation record for quicksort(l, 3). Notice that the display pointers "cross"; that is, d points further down the stack than d does. However, that is a proper situation; exchange can only access its own data and that of sort, via d[l].