{"id":110925,"date":"2025-03-03T07:00:00","date_gmt":"2025-03-03T15:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=110925"},"modified":"2025-03-03T11:01:10","modified_gmt":"2025-03-03T19:01:10","slug":"20250303-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20250303-00\/?p=110925","title":{"rendered":"Lexically scoped functions accessing parent locals: The display"},"content":{"rendered":"<p>Some time ago, I discussed how <a title=\"What is a static chain pointer in the context of calling convention ABI?\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20231204-00\/?p=109095\"> the static chain pointer<\/a> is used to access local variables of lexical parent functions, for languages like Pascal that support it. In a later article, I discussed how <a title=\"The mysterious second parameter to the x86 ENTER instruction\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20231211-00\/?p=109126\"> the mysterious second parameter to the x86 <code>ENTER<\/code> instruction<\/a> accomplishes the same task, but in a different way.<\/p>\n<p>There is yet another popular way to implement this feature, known as the <i>display<\/i>, a name that comes from the final paragraph of the paper <a title=\"Recursive Programming\" href=\"https:\/\/ics.uci.edu\/~jajones\/INF102-S18\/readings\/07_dijkstra.pdf\"> <i>Recursive Programming<\/i><\/a> by Edsger Dijkstra.\u00b9<\/p>\n<p>The idea is that you have a reserved array of pointers known as the display, its size equal to the maximum depth of lexically scoped functions. If a function has inner functions, then it stores a pointer to its stack frame in the display at an index corresponding to its depth, where the &#8220;depth&#8221; of a function is the number of enclosing lexical parent functions. For example, a global function has depth zero since it has no lexical parents. When the function returns it restores the original value to the display slot.<\/p>\n<p>Let&#8217;s walk through this design with our example.<\/p>\n<pre>function Outer(n: integer) : integer;\r\n    var i: integer;\r\n\r\n    procedure Update(j: integer);\r\n    begin\r\n        i := i + j\r\n    end;\r\n\r\n    procedure Inner(m: integer);\r\n\r\n        procedure MoreInner;\r\n        begin\r\n            Update(m)\r\n        end;\r\n\r\n    (* Inner body begins here *)\r\n    begin\r\n        MoreInner\r\n    end;\r\n\r\n(* Outer body begins here *)\r\nbegin\r\n    i := 0;\r\n    Inner(n);\r\n    Outer := i\r\nend;\r\n<\/pre>\n<p>The function <code>Outer<\/code> is not lexically enclosed in any other function, so its depth is zero. Its lexical children are then assigned a depth depending on how many frames they are away from that starting point.<\/p>\n<div id=\"p20250303_head\" style=\"display: none;\">\u00a0<\/div>\n<table style=\"border-collapse: collapse; text-align: center;\" border=\"0\" cellspacing=\"3\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td style=\"border: solid 1px currentcolor;\">Outer<\/td>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td align=\"left\">Depth 0<\/td>\n<\/tr>\n<tr>\n<td>\u2193<\/td>\n<td>\u2198<\/td>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px currentcolor;\">Update<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px currentcolor;\">Inner<\/td>\n<td>&nbsp;<\/td>\n<td align=\"left\">Depth 1<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td>\u2193<\/td>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px currentcolor;\">MoreInner<\/td>\n<td>&nbsp;<\/td>\n<td align=\"left\">Depth 2<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Let&#8217;s walk through a call to <code>Outer<\/code>.<\/p>\n<p>Initially, the display looks like this:<\/p>\n<table class=\"cp3\" style=\"border-collapse: collapse;\" border=\"1\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td>0<\/td>\n<td>mystery0<\/td>\n<\/tr>\n<tr>\n<td>1<\/td>\n<td>mystery1<\/td>\n<\/tr>\n<tr>\n<td>2<\/td>\n<td>mystery2<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>The <code>Outer<\/code> function saves the value in display slot zero (<code>mystery0<\/code>) and replaces it with a pointer to its stack frame.<\/p>\n<table class=\"cp3\" style=\"border-collapse: collapse;\" border=\"1\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td>0<\/td>\n<td><tt>Outer<\/tt> frame \u2190<\/td>\n<\/tr>\n<tr>\n<td>1<\/td>\n<td>mystery1<\/td>\n<\/tr>\n<tr>\n<td>2<\/td>\n<td>mystery2<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>When <code>Outer<\/code> calls <code>Inner<\/code>, the <code>Inner<\/code> procedure saves the value in display slot one (<code>mystery1<\/code>) and replaces it with a pointer to the <code>Inner<\/code> stack frame.<\/p>\n<table class=\"cp3\" style=\"border-collapse: collapse;\" border=\"1\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td>0<\/td>\n<td><tt>Outer<\/tt> frame<\/td>\n<\/tr>\n<tr>\n<td>1<\/td>\n<td><tt>Inner<\/tt> frame \u2190<\/td>\n<\/tr>\n<tr>\n<td>2<\/td>\n<td>mystery2<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Next, <code>Inner<\/code> calls <code>MoreInner<\/code>. This time, <code>MoreInner<\/code> has no inner functions of its own, so it doesn&#8217;t have to do anything with the display.<\/p>\n<p>Now things get interesting. How does <code>MoreInner<\/code> load the value of <code>m<\/code>? Well, <code>m<\/code> is a parameter in <code>Inner<\/code>&#8216;s stack frame, and <code>Inner<\/code> is at depth one, so <code>MoreInner<\/code> reads the pointer at index 1 in the display pointers and uses it to read <code>m<\/code> from the <code>Inner<\/code> stack frame.<\/p>\n<p>Okay, now we have a call to <code>Update<\/code>, which is at depth one, so it saves the value in display slot one (which is a pointer to <code>Inner<\/code>&#8216;s frame) and replaces it with a pointer to <code>Update<\/code>&#8216;s frame.<\/p>\n<table class=\"cp3\" style=\"border-collapse: collapse;\" border=\"1\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td>0<\/td>\n<td><tt>Outer<\/tt> frame<\/td>\n<\/tr>\n<tr>\n<td>1<\/td>\n<td><tt>Update<\/tt> frame \u2190<\/td>\n<\/tr>\n<tr>\n<td>2<\/td>\n<td>mystery2<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>To find the <code>i<\/code> variable in <code>Outer<\/code>&#8216;s frame, <code>Update<\/code> realizes that <code>Outer<\/code> is a depth zero function, so it looks for the pointer in display slot zero (which is a pointer to <code>Outer<\/code>&#8216;s frame) to locate the <code>i<\/code> variable and add <code>j<\/code> to it.<\/p>\n<p>Now that the work is done, <code>Update<\/code> restores the saved value to display slot one (<code>Inner<\/code> frame) and returns to <code>MoreInner<\/code>.<\/p>\n<table class=\"cp3\" style=\"border-collapse: collapse;\" border=\"1\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td>0<\/td>\n<td><tt>Outer<\/tt> frame<\/td>\n<\/tr>\n<tr>\n<td>1<\/td>\n<td><tt>Inner<\/tt> frame \u2190<\/td>\n<\/tr>\n<tr>\n<td>2<\/td>\n<td>mystery2<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>If <code>MoreInner<\/code> had more work to do, it could use display slots 0 and 1 to access the variables of <code>Outer<\/code> and <code>Inner<\/code>. But it doesn&#8217;t. So it just returns.<\/p>\n<table class=\"cp3\" style=\"border-collapse: collapse;\" border=\"1\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td>0<\/td>\n<td><tt>Outer<\/tt> frame<\/td>\n<\/tr>\n<tr>\n<td>1<\/td>\n<td><tt>Inner<\/tt> frame<\/td>\n<\/tr>\n<tr>\n<td>2<\/td>\n<td>mystery2<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Similarly <code>Inner<\/code> is finished and restores its saved value to display slot 1 before returning.<\/p>\n<table class=\"cp3\" style=\"border-collapse: collapse;\" border=\"1\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td>0<\/td>\n<td><tt>Outer<\/tt> frame<\/td>\n<\/tr>\n<tr>\n<td>1<\/td>\n<td>mystery1 \u2190<\/td>\n<\/tr>\n<tr>\n<td>2<\/td>\n<td>mystery2<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Finally, <code>Outer<\/code> fetches the value from its <code>i<\/code> variable (which <code>Update<\/code> conveniently updated) and uses it as the return value. Before returning, it restores display slot zero.<\/p>\n<table class=\"cp3\" style=\"border-collapse: collapse;\" border=\"1\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td>0<\/td>\n<td>mystery0 \u2190<\/td>\n<\/tr>\n<tr>\n<td>1<\/td>\n<td>mystery1<\/td>\n<\/tr>\n<tr>\n<td>2<\/td>\n<td>mystery2<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Notice that whenever a depth <var>N<\/var> function is active, only the first <var>N+1<\/var> display slots are meaningful.<\/p>\n<p>Originally, the display was a global variable with a fixed number of slots, which caps the depth of lexically nested functions.\u00b3 Accessing a variable from an outer frame requires only one added indirection (through the display). It does cost a load from a global variable, which depending on your processor architecture might be easy (if your processor supports absolute addressing or instruction pointer-relative addressing with a large enough reach), or annoying (if you have to calculate the address separately).<\/p>\n<p>Making the display global precludes multi-threaded operations. Most implementations have the function at depth zero allocate the display in its own frame, then have all inner functions receive the address of that display as a hidden parameter.<\/p>\n<p>\u00b9 Reading that document has a similar feeling to reading centuries-old scientific documents.\u00b2 The terminology and style of writing is so different that you spend a good amount of mental effort translating the text into modern terminology: &#8220;The program for subroutine <i>A<\/i> can only be executed correctly if the current value of the parameter pointer is at the disposal of the arithmetic unit, in other words, the parameter pointer can be regarded as one of the aspects of the state of the arithmetic unit, and it must therefore be recorded amongst the link data.&#8221; Translation into modern language: &#8220;The frame pointer must be kept in a CPU register and stored in the stack frame.&#8221;<\/p>\n<p>\u00b2 For example, here&#8217;s <a title=\"The Mathematical Principles of Natural Philosophy (1729)\/Book 1\/Section 2: Proposition IV. Theorem IV.\" href=\"https:\/\/en.wikisource.org\/wiki\/The_Mathematical_Principles_of_Natural_Philosophy_(1729)\/Book_1\/Section_2#Prop4\"> Proposition IV. Theorem IV<\/a> from Isaac Newton&#8217;s <i>Principia<\/i>: &#8220;The centripetal forces of bodies, which by equoble motions describe different circles, tend to the centres of the same circles; and are one to the other, as the squares of the arcs described in equal times applied to the radii applied the circles.&#8221; In modern terms, this is saying that centripetal acceleration is toward the center of the circle and is proportional to <var>s<\/var>\u00b2\/<var>r<\/var>, where <var>s<\/var> is the distance travelled over a fixed period of time, and <var>r<\/var> is the radius.<\/p>\n<p>And that&#8217;s one of the easy ones! Corollary 6 reads, &#8220;If the periodic times are in the sesquiplicate ratio of the radii, and therefore the velocities reciprocally in the subduplicate ratio of the radii; the centripetal forces will be in the duplicate ratio of the radii inversely: and the contrary.&#8221; Good luck with that.<\/p>\n<p>\u00b3 If each module provides its own display, then you can have each module&#8217;s display be exactly the size of the deepest lexical nesting in that module.<\/p>\n<p>\n<script>\nwindow.addEventListener(\"load\", function() {\n  var fullFF = getComputedStyle(document.body).fontFamily;\n  var simpleFF = fullFF.replace(\/ Emoji\/g, \"\");\n  \/\/ break up \"style\" to prevent wordpress from injecting random junk\n  document.getElementById(\"p20250303_head\").innerHTML =\n`<s` + `tyle>\nbody { font-family: ${simpleFF}; }\n.emoji { font-family: ${fullFF}; }\n<\/s` + `tyle>`;\n});\n<\/script><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Using a well-known location instead of copying frame pointers.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-110925","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Using a well-known location instead of copying frame pointers.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/110925","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=110925"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/110925\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=110925"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=110925"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=110925"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}