2 |
7u83 |
1 |
<!-- Crown Copyright (c) 1998 -->
|
|
|
2 |
<HTML>
|
|
|
3 |
<HEAD>
|
|
|
4 |
<TITLE>Procedures and Locals</TITLE>
|
|
|
5 |
</HEAD>
|
|
|
6 |
<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#0000FF" VLINK="#400080" ALINK="#FF0000">
|
|
|
7 |
<A NAME=S37>
|
|
|
8 |
<H1>TDF Guide, Issue 4.0 </H1>
|
|
|
9 |
<H3>January 1998</H3>
|
|
|
10 |
<A HREF="guide8.html"><IMG SRC="../images/next.gif" ALT="next section">
|
|
|
11 |
</A> <A HREF="guide6.html">
|
|
|
12 |
<IMG SRC="../images/prev.gif" ALT="previous section"></A>
|
|
|
13 |
<A HREF="guide1.html"><IMG SRC="../images/top.gif" ALT="current document"></A>
|
|
|
14 |
<A HREF="../index.html"><IMG SRC="../images/home.gif" ALT="TenDRA home page">
|
|
|
15 |
</A>
|
|
|
16 |
<IMG SRC="../images/no_index.gif" ALT="document index"><P>
|
|
|
17 |
<HR>
|
|
|
18 |
<DL>
|
|
|
19 |
<DT><A HREF="#S38"><B>5.1 </B> - make_proc and apply_proc</A>
|
|
|
20 |
<DD>
|
|
|
21 |
<DT><A HREF="#S39"><B>5.1.1 </B> - vartag, varparam
|
|
|
22 |
</A><DD>
|
|
|
23 |
<DT><A HREF="#S40"><B>5.2 </B> - make_general_proc and apply_general_proc</A>
|
|
|
24 |
<DD>
|
|
|
25 |
<DT><A HREF="#S41"><B>5.2.1 </B> - tail_call</A><DD>
|
|
|
26 |
<DT><A HREF="#S42"><B>5.2.2 </B> - PROCPROPS</A><DD>
|
|
|
27 |
<DT><A HREF="#S43"><B>5.3 </B> - Defining and using locals</A><DD>
|
|
|
28 |
<DT><A HREF="#S44"><B>5.3.1 </B> - identify, variable</A><DD>
|
|
|
29 |
<DT><A HREF="#S45"><B>5.3.2 </B> - ACCESS</A><DD>
|
|
|
30 |
<DT><A HREF="#S46"><B>5.3.2.1 </B> - Locals model</A><DD>
|
|
|
31 |
<DT><A HREF="#S47"><B>5.3.2.2 </B> - Access "hints"
|
|
|
32 |
</A><DD>
|
|
|
33 |
<DT><A HREF="#S48"><B>5.3.3 </B> - current_env, env_offset</A>
|
|
|
34 |
<DD>
|
|
|
35 |
<DT><A HREF="#S49"><B>5.3.4 </B> - local_alloc, local_free_all, last_local</A>
|
|
|
36 |
<DD>
|
|
|
37 |
<DT><A HREF="#S50"><B>5.4 </B> - Heap storage</A><DD>
|
|
|
38 |
</DL>
|
|
|
39 |
<HR>
|
|
|
40 |
<H1>5 Procedures and Locals</H1>
|
|
|
41 |
All procedures in TDF are essentially global; the only values which
|
|
|
42 |
are accessible from the body of a procedure are those which are derived
|
|
|
43 |
from global TAGs (introduced by TAGDEFs or TAGDECs), local TAGs defined
|
|
|
44 |
within the procedure and parameter TAGs of the procedure<P>
|
|
|
45 |
All executable code in TDF will arise from an EXP PROC made by either
|
|
|
46 |
make_proc or make_general_proc. They differ in their treatment of
|
|
|
47 |
how space for the actual parameters of a call is managed; in particular,
|
|
|
48 |
is it the caller or the callee which deallocates the parameter space?<P>
|
|
|
49 |
With make_proc, this management is conceptually done by the caller
|
|
|
50 |
at an apply_proc; i.e. the normal C situation. This suffers from the
|
|
|
51 |
limitation that tail-calls of procedures are then only possible in
|
|
|
52 |
restricted circumstances (e.g. the space for the parameters of the
|
|
|
53 |
tail-call must be capable of being included in caller's parameters)
|
|
|
54 |
and could only be implemented as an optimisation within a translator.
|
|
|
55 |
A producer could not predict these circumstances in a machine independent
|
|
|
56 |
manner, whether or not it knew that a tail-call was valid.<P>
|
|
|
57 |
An alternative would be to make the management of parameter space
|
|
|
58 |
the responsibility of the called procedure. Rather than do this, make_general_proc
|
|
|
59 |
(and apply_general_proc) splits the parameters into two sets, one
|
|
|
60 |
whose allocation is the responsibility of the caller and the other
|
|
|
61 |
whose allocation is dealt with by the callee. This allows an explicit
|
|
|
62 |
tail_call to be made to a procedure with new callee parameters; the
|
|
|
63 |
caller parameters for the tail_call will be the same as (or some initial
|
|
|
64 |
subset of) the caller parameters of the procedure containing the tail_call
|
|
|
65 |
.<P>
|
|
|
66 |
A further refinement of make_general_proc is to allow access to the
|
|
|
67 |
caller parameter space in a postlude at the call of the procedure
|
|
|
68 |
using an apply_general_proc. This allows simple implementations of
|
|
|
69 |
Ada out_parameters, or more generally, multiple results of procedures.<P>
|
|
|
70 |
<A NAME=S38>
|
|
|
71 |
<HR><H2>5.1. make_proc and apply_proc</H2>
|
|
|
72 |
The make_proc constructor has signature:<P>
|
|
|
73 |
<PRE>
|
|
|
74 |
<I> result_shape</I>: SHAPE
|
|
|
75 |
<I> params_intro</I>: LIST(TAGSHACC)
|
|
|
76 |
<I> var_intro</I>: OPTION(TAGACC)
|
|
|
77 |
<I> body</I>: EXP BOTTOM
|
|
|
78 |
-> EXP PROC
|
|
|
79 |
</PRE>
|
|
|
80 |
The <I>params_intro</I> and <I>var_intro</I> parameters introduce
|
|
|
81 |
the formal parameters of the procedure which may be used in <I>body</I>.
|
|
|
82 |
The procedure result will have SHAPE <I>result_shape</I> and will
|
|
|
83 |
be usually given by some return construction within <I>body</I>. The
|
|
|
84 |
basic model is that space will be provided to copy actual parameters
|
|
|
85 |
(into space supplied by some apply_proc) by value into these formals
|
|
|
86 |
and the body will treat this space effectively as local variables.
|
|
|
87 |
<P>
|
|
|
88 |
Each straightforward formal parameter is introduced by an auxiliary
|
|
|
89 |
SORT TAGSHACC using make_tagshacc:<P>
|
|
|
90 |
<PRE>
|
|
|
91 |
<I>sha</I>: SHAPE
|
|
|
92 |
<I>opt_access</I>: OPTION(LIST(ACCESS))
|
|
|
93 |
<I>tg_intro</I>: TAG POINTER(alignment(<I>sha</I>))
|
|
|
94 |
-> TAGSHACC
|
|
|
95 |
</PRE>
|
|
|
96 |
<P>
|
|
|
97 |
Within <I>body</I>, the formal will be accessed using <I>tg_intro</I>;
|
|
|
98 |
it is always considered to be a pointer to the space of SHAPE <I>sha</I>
|
|
|
99 |
allocated by apply_proc, hence the pointer SHAPE. <P>
|
|
|
100 |
For example, if we had a simple procedure with one integer parameter,
|
|
|
101 |
<I>var_intro</I> would be empty and <I>params_intro</I> might be:<P>
|
|
|
102 |
<PRE>
|
|
|
103 |
<I>params_intro</I> = make_tagshacc<I>(</I> integer(v), empty, make_tag(13))
|
|
|
104 |
</PRE>
|
|
|
105 |
Then, TAG 13 from the enclosing UNIT's name-space is identified with
|
|
|
106 |
the formal parameter with SHAPE POINTER(INTEGER(v)). Any use of obtain_tag(make_tag(13))
|
|
|
107 |
in <I>body</I> will deliver a pointer to the integer parameter. I
|
|
|
108 |
shall return to the meaning of <I>opt_access</I> and the ramifications
|
|
|
109 |
of the scope and extent of TAGs involved in conjunction with local
|
|
|
110 |
declarations in <A HREF="#35">section 5.3.1 on page 30</A>.<P>
|
|
|
111 |
Procedures, whether defined by make_proc or make_general_proc, will
|
|
|
112 |
usually terminate and deliver its result with a return:<P>
|
|
|
113 |
<PRE>
|
|
|
114 |
<I> arg1</I>: EXP <I>x</I>
|
|
|
115 |
-> EXP BOTTOM
|
|
|
116 |
</PRE>
|
|
|
117 |
Here <I>x</I> must be identical to the <I>result_shape</I> of the
|
|
|
118 |
call of the procedure There may be several returns in body; and the
|
|
|
119 |
SHAPE <I>x</I> in each will be the same. Some languages allow different
|
|
|
120 |
types to be returned depending on the particular call. The producer
|
|
|
121 |
must resolve this issue. For example, C allows one to deliver void
|
|
|
122 |
if the resulting value is not used. In TDF a dummy value must be provided
|
|
|
123 |
at the return; for example make_value(<I>result_shape</I>)<P>
|
|
|
124 |
Note that the <I>body</I> has SHAPE bottom since all possible terminations
|
|
|
125 |
to a procedure have SHAPE BOTTOM..<P>
|
|
|
126 |
Procedures defined by make_proc are called using apply_proc:
|
|
|
127 |
<P>
|
|
|
128 |
<PRE>
|
|
|
129 |
<I> result_shape</I>: SHAPE
|
|
|
130 |
<I> arg1</I>: EXP PROC
|
|
|
131 |
<I> arg2</I>: LIST(EXP)
|
|
|
132 |
<I> varparam</I>: OPTION(EXP)
|
|
|
133 |
--> EXP <I>result_shape</I>
|
|
|
134 |
</PRE>
|
|
|
135 |
Here <I>arg1</I> is the procedure to be called and <I>arg2</I> gives
|
|
|
136 |
the actual parameters. There must be at least as many actual parameters
|
|
|
137 |
as given (with the same SHAPE) in the <I>params_intro</I> of the corresponding
|
|
|
138 |
make_proc for arg1
|
|
|
139 |
<A NAME=footnote74 HREF="footnote.html#74">*</A>. The values of <I>arg2</I>
|
|
|
140 |
will be copied into space managed by caller.
|
|
|
141 |
<P>
|
|
|
142 |
The SHAPE of the result of the call is given by <I>result_shape</I>
|
|
|
143 |
which must be identical to the <I>result_shape</I> of the make_proc.<P>
|
|
|
144 |
<A NAME=S39>
|
|
|
145 |
<H3>5.1.1. <I><A NAME=12>vartag</I>, <I>varparam
|
|
|
146 |
</I> </H3>
|
|
|
147 |
Use of the <I>var_intro</I> OPTION in make_proc and the corresponding
|
|
|
148 |
<I>varparam</I> in apply_proc allows one to have a parameter of any
|
|
|
149 |
SHAPE, possibly differing from call to call where the actual SHAPE
|
|
|
150 |
can be deduced in some way by the <I>body</I> of the make_proc . One
|
|
|
151 |
supplies an extra actual parameter, <I>varparam</I>, which usually
|
|
|
152 |
would be a structure grouping some set of values. The body of the
|
|
|
153 |
procedure can then access these values using the pointer given by
|
|
|
154 |
the TAG <I>var_intro</I>, using add_to_ptr with some computed offsets
|
|
|
155 |
to pick out the individual fields. <P>
|
|
|
156 |
This is a slightly different method of giving a variable number of
|
|
|
157 |
parameters to a procedure, rather than simply giving more actuals
|
|
|
158 |
than formals. The principle difference is in the alignment of the
|
|
|
159 |
components of <I>varparam</I>; these will be laid out according to
|
|
|
160 |
the default padding defined by the component shapes. In most ABIs,
|
|
|
161 |
this padding is usually different to the way parameters are laid out;
|
|
|
162 |
for example, character parameters are generally padded out to a full
|
|
|
163 |
word. Thus a sequence of parameters of given shape has a different
|
|
|
164 |
layout in store to the same sequence of shapes in a structure. If
|
|
|
165 |
one wished to pass an arbitrary structure to a procedure, one would
|
|
|
166 |
use the <I>varparam</I> option rather passing the fields individually
|
|
|
167 |
as extra actual parameters.<P>
|
|
|
168 |
<A NAME=S40>
|
|
|
169 |
<HR><H2>5.2. make_general_proc and apply_general_proc</H2>
|
|
|
170 |
A make_general_proc has signature:<P>
|
|
|
171 |
<PRE>
|
|
|
172 |
<I>result_shape</I>: SHAPE
|
|
|
173 |
<I>prcprops</I>: OPTION(PROCPROPS)
|
|
|
174 |
<I>caller_intro</I>: LIST(TAGSHACC)
|
|
|
175 |
<I>callee_intro</I>: LIST(TAGSHACC)
|
|
|
176 |
<I>body</I>: EXP BOTTOM
|
|
|
177 |
-> EXP PROC
|
|
|
178 |
</PRE>
|
|
|
179 |
Here the formal parameters are split into two sets, <I>caller_intro</I>
|
|
|
180 |
and <I>callee_intro</I>, each given by a list of TAGSHACCs just as
|
|
|
181 |
in make_proc. The distinction between the two sets is that the make_general_proc
|
|
|
182 |
is responsible for de_allocating any space required for the callee
|
|
|
183 |
parameter set; this really only becomes obvious at uses of tail_call
|
|
|
184 |
within <I>body.</I> <P>
|
|
|
185 |
The <I>result_shape</I> and <I>body</I> have the same general properties
|
|
|
186 |
as in make_proc. In addition <I>prcprops</I> gives other information
|
|
|
187 |
both about <I>body</I> and the way that that the procedure is called.
|
|
|
188 |
PROCPROPS are a set drawn from check_stack, inline, no_long_jump_dest,
|
|
|
189 |
untidy, var_callees and var_callers. The set is composed using add_procprops.
|
|
|
190 |
The PROCPROPS no_long_jump_dest is a property of <I>body</I> only;
|
|
|
191 |
it indicates that none of the labels within <I>body</I> will be the
|
|
|
192 |
target of a long_jump construct. The other properties should also
|
|
|
193 |
be given consistently at all calls of the procedure; theu are discussed
|
|
|
194 |
in <A HREF="#24">section 5.2.2 on page 29</A>.<P>
|
|
|
195 |
A procedure, <I>p</I>, constructed by make_general_proc is called
|
|
|
196 |
using apply_general_proc: <P>
|
|
|
197 |
<PRE>
|
|
|
198 |
<I>result_shape</I>: SHAPE
|
|
|
199 |
<I>prcprops</I>: OPTION(PROCPROPS)
|
|
|
200 |
<I>p</I>: EXP PROC
|
|
|
201 |
<I>caller_params</I>: LIST(OTAGEXP)
|
|
|
202 |
<I>callee_params</I>: CALLEES
|
|
|
203 |
<I>postlude</I>: EXP TOP
|
|
|
204 |
-> EXP <I>result_shape</I>
|
|
|
205 |
</PRE>
|
|
|
206 |
The actual caller parameters are given by <I>caller_params</I> as
|
|
|
207 |
a list of OTAGEXPs constructed using make_otagexp:<P>
|
|
|
208 |
<PRE>
|
|
|
209 |
<I>tgopt</I>: OPTION(TAG <I>x</I>)
|
|
|
210 |
<I>e</I>: EXP <I>x</I>
|
|
|
211 |
-> OTAGEXP
|
|
|
212 |
</PRE>
|
|
|
213 |
Here, <I>e</I> is the value of the parameter and <I>tgopt</I>, if
|
|
|
214 |
present, is a TAG which will bound to the final value of the parameter
|
|
|
215 |
(after <I>body</I> is evaluated) in the <I>postlude</I> expression
|
|
|
216 |
of the apply_general_proc
|
|
|
217 |
<A NAME=footnote75 HREF="footnote.html#75">*</A>. Clearly, this allows
|
|
|
218 |
one to use a caller parameter as an extra result of the procedure;
|
|
|
219 |
for example, as in Ada out-parameters.<P>
|
|
|
220 |
The actual <I>callee_params</I> may be constructed in three different
|
|
|
221 |
ways. The usual method is to use make_callee_list, giving a list of
|
|
|
222 |
actual EXP parameters, corresponding to the <I>caller_intro</I>
|
|
|
223 |
list in the obvious way.The constructor, same_callees allows one to
|
|
|
224 |
use the callees of the current procedure as the callees of the call;
|
|
|
225 |
this, of course, assumes that the formals of the current procedure
|
|
|
226 |
are compatible with the formals required for the call The final method
|
|
|
227 |
allows one to construct a dynamically sized set of CALLEES; make_dynamic_callees
|
|
|
228 |
takes a pointer and a size (expressed as an OFFSET) to make the CALLEES;
|
|
|
229 |
this will be used in conjunction with a var_callees PROCPROPS (see
|
|
|
230 |
<A HREF="#24">section 5.2.2 on page 29</A>).<P>
|
|
|
231 |
Some procedures can be expressed using either make_proc or make_general_proc.
|
|
|
232 |
For example:<P>
|
|
|
233 |
make_proc(S, L, empty, B) = make_general_proc(S, var_callers, L, empty,
|
|
|
234 |
B)<P>
|
|
|
235 |
<A NAME=S41>
|
|
|
236 |
<H3>5.2.1. tail_call</H3>
|
|
|
237 |
Often the result of a procedure, <I>f</I>, is simply given by the
|
|
|
238 |
call of another (or the same) procedure, <I>g</I>. In appropriate
|
|
|
239 |
circumstances, the same stack space can be used for the call of <I>g</I>
|
|
|
240 |
as the call of <I>f</I>. This can be particularly important where
|
|
|
241 |
heavily recursive routines are involved; some languages even use tail
|
|
|
242 |
recursion as the preferred method of looping.<P>
|
|
|
243 |
One condition for such a tail call to be applicable is knowing that
|
|
|
244 |
<I>g</I> does not require any pointers to locals of <I>f</I>; this
|
|
|
245 |
is often implicit in the language involved. Equally important is that
|
|
|
246 |
the action on the return from <I>f</I> is indistiguishable from the
|
|
|
247 |
return from <I>g</I>. For example, if it were the callers responsibility
|
|
|
248 |
to pop the the space for the parameters on return from a call, then
|
|
|
249 |
the tail call of <I>g</I> would only work if <I>g</I> had the same
|
|
|
250 |
parameter space as <I>f</I>.<P>
|
|
|
251 |
This is the justification for splitting the parameter set of a general
|
|
|
252 |
proc; it is (at least conceptually) the caller's responsibility for
|
|
|
253 |
popping the caller-parameters only - the callee-parameters are dealt
|
|
|
254 |
with by the procedure itself. Hence we can define tail_call which
|
|
|
255 |
uses the same caller-parameters, but a different set of callee-parameters:
|
|
|
256 |
<P>
|
|
|
257 |
<PRE>
|
|
|
258 |
<I>prcprops</I>: OPTION(PROCPROPS)
|
|
|
259 |
<I>p</I>: EXP PROC
|
|
|
260 |
<I>callee_params</I>: CALLEES
|
|
|
261 |
-> EXP BOTTOM
|
|
|
262 |
</PRE>
|
|
|
263 |
The procedure p will be called with the same caller parameters as
|
|
|
264 |
the current procedure and the new <I>callee_params</I> and return
|
|
|
265 |
to the call site of the current procedure. Semantically, if S is the
|
|
|
266 |
return SHAPE of the current procedure, and L is its caller-parameters:<P>
|
|
|
267 |
tail_call(P, p, C) = return(apply_general_proc(S, P, p, L, C, make_top()))<P>
|
|
|
268 |
However an implementation is expected to conserve stack by using the
|
|
|
269 |
same space for the call of p as the current procedure.<P>
|
|
|
270 |
<P>
|
|
|
271 |
<A NAME=S42>
|
|
|
272 |
<H3>5.2.2. <A NAME=24>PROCPROPS</H3>
|
|
|
273 |
The presence of var_callees (or var_callers) means that the procedure
|
|
|
274 |
can be called with more actual callee (or caller) parameters than
|
|
|
275 |
are indicated in <I>callee_intro</I> (or <I>caller_intro
|
|
|
276 |
</I>). These extra parameters would be accessed within body using
|
|
|
277 |
offset calculations with respect to the named parameters. The offsets
|
|
|
278 |
should be calculated using parameter_alignment to give the packing
|
|
|
279 |
of the parameter packs.<P>
|
|
|
280 |
The presence of untidy means that <I>body</I> may be terminated by
|
|
|
281 |
an untidy_return. This returns the result of the procedure as in return,
|
|
|
282 |
but the lifetime of the local space of the procedure is extended (in
|
|
|
283 |
practice this is performed by not returning the stack to its original
|
|
|
284 |
value at the call). A procedure containing an untidy_return is a generalisation
|
|
|
285 |
of a local_alloc(see
|
|
|
286 |
<A HREF="#60">section 5.3.4 on page 32</A>). For example the procedure
|
|
|
287 |
could do some complicated local allocation (a triangular array, say)
|
|
|
288 |
and untidily return a pointer to it so that the space is still valid
|
|
|
289 |
in the calling procedure. The space will remain valid for the lifetime
|
|
|
290 |
of the calling procedure unless some local_free is called within it,
|
|
|
291 |
just as if the space had been generated by a local_alloc in the calling
|
|
|
292 |
procedure.<P>
|
|
|
293 |
The presence of inline is just a hint to the translator that the procedure
|
|
|
294 |
body is a good candidate for inlining at the call.<P>
|
|
|
295 |
The presence of check_stack means that the static stack requirements
|
|
|
296 |
of the procedure will be checked on entry to see that they do not
|
|
|
297 |
exceed the limits imposed by set_stack_limit; if they are exceeded
|
|
|
298 |
a TDF exception with ERROR_CODE stack_overflow (see <A HREF="guide8.html#31">section
|
|
|
299 |
6.3 on page 35</A>) will be raised.<P>
|
|
|
300 |
<A NAME=S43>
|
|
|
301 |
<HR><H2>5.3. <A NAME=34>Defining and using locals</H2>
|
|
|
302 |
<A NAME=S44>
|
|
|
303 |
<H3>5.3.1. <A NAME=35>identify, variable</H3>
|
|
|
304 |
Local definitions within the <I>body</I> of a procedure are given
|
|
|
305 |
by two EXP constructors which permit one to give names to values over
|
|
|
306 |
a scope given by the definition. Note that this is somewhat different
|
|
|
307 |
to declarations in standard languages where the declaration is usually
|
|
|
308 |
embedded in a larger construct which defines the scope of the name;
|
|
|
309 |
here the scope is explicit in the definition. The reason for this
|
|
|
310 |
will become more obvious in the discussion of TDF transformations.
|
|
|
311 |
The simpler constructor is identify:<P>
|
|
|
312 |
<PRE>
|
|
|
313 |
<I> opt_access</I>: OPTION(ACCESS)
|
|
|
314 |
<I> name_intro</I>: TAG<I> x</I>
|
|
|
315 |
<I> definition</I>: EXP <I>x</I>
|
|
|
316 |
<I> body</I>: EXP <I>y</I>
|
|
|
317 |
-> EXP<I> y</I>
|
|
|
318 |
</PRE>
|
|
|
319 |
The <I>definition</I> is evaluated and its result is identified with
|
|
|
320 |
the TAG given by <I>name_intro</I> within its scope <I>body</I>. Hence
|
|
|
321 |
the use of any obtain_tag(<I>name_intro</I>) within
|
|
|
322 |
<I>body</I> is equivalent to using this result. Anywhere else, obtain_tag(<I>name_intro
|
|
|
323 |
</I>) is meaningless, including in other procedures.<P>
|
|
|
324 |
The other kind of local definition is variable:<P>
|
|
|
325 |
<PRE>
|
|
|
326 |
<I> opt_access</I>: OPTION(ACCESS)
|
|
|
327 |
<I> name_intro</I>: TAG<I> x</I>
|
|
|
328 |
<I> init</I>: EXP <I>x</I>
|
|
|
329 |
<I> body</I>: EXP <I>y</I>
|
|
|
330 |
-> EXP<I> y</I>
|
|
|
331 |
</PRE>
|
|
|
332 |
Here the <I>init</I> EXP is evaluated and its result serves as an
|
|
|
333 |
initialisation of space of SHAPE <I>x</I> local to the procedure.
|
|
|
334 |
The TAG name_intro is then identified with a pointer to that SPACE
|
|
|
335 |
within body. A use of obtain_tag(<I>name_intro</I>) within <I>body</I>
|
|
|
336 |
is equivalent to using this pointer and is meaningless outside <I>body</I>
|
|
|
337 |
or in other procedures. Many variable declarations in programs are
|
|
|
338 |
uninitialised; in this case, the <I>init</I> argument could be provided
|
|
|
339 |
by make_value which will produce some value with SHAPE given by its
|
|
|
340 |
parameter.<P>
|
|
|
341 |
<A NAME=S45>
|
|
|
342 |
<H3>5.3.2. <A NAME=40>ACCESS</H3>
|
|
|
343 |
The ACCESS SORT given in tag declarations is a way of describing a
|
|
|
344 |
list of properties to be associated with the tag. They are basically
|
|
|
345 |
divided into two classes, one which describes global properties of
|
|
|
346 |
the tag with respect to the model for locals and the other which gives
|
|
|
347 |
"hints" on how the value will be used. Any of these can
|
|
|
348 |
be combined using add_access.<P>
|
|
|
349 |
<A NAME=S46>
|
|
|
350 |
<H4>5.3.2.1 . Locals model</H4>
|
|
|
351 |
At the moment there are just three possibilities in the first class
|
|
|
352 |
of ACCESS constructors. They are standard_access (the default) , visible,
|
|
|
353 |
out_par and long_jump_access.
|
|
|
354 |
<P>
|
|
|
355 |
The basic model used for the locals and parameters of a procedure
|
|
|
356 |
is a frame within a stack of nested procedure calls. One could implement
|
|
|
357 |
a procedure by allocating space according to SHAPEs of all of the
|
|
|
358 |
parameter and local TAGs so that the corresponding values are at fixed
|
|
|
359 |
offsets either from the start of the frame or some pointer within
|
|
|
360 |
it.<P>
|
|
|
361 |
Indeed, if the ACCESS <I>opt_access </I>parameter in a TAG definition
|
|
|
362 |
is produced by visible, then a translator is almost bound to do just
|
|
|
363 |
that for that TAG. This is because it allows for the possibility of
|
|
|
364 |
the value to be accessed in some way other than by using obtain_tag
|
|
|
365 |
which is the standard way of recovering the value bound to the TAG.
|
|
|
366 |
The principal way that this could happen within TDF is by the combined
|
|
|
367 |
use of env_offset to give the offset and current_env to give a pointer
|
|
|
368 |
to the current frame (see <A HREF="#57">section 5.3.3 on page 31</A>).
|
|
|
369 |
<P>
|
|
|
370 |
The out_par ACCESS is only applicable to caller parameters of procedures;
|
|
|
371 |
it indicates that the value of the TAG concerned will accessed by
|
|
|
372 |
the postlude part of an apply_general_proc. Hence, the value of the
|
|
|
373 |
parameter must be accessible after the call; usually this will be
|
|
|
374 |
on the stack in the callers frame.<P>
|
|
|
375 |
The long_jump_access flag is used to indicate that the tag must be
|
|
|
376 |
available after a long_jump. In practice, if either visible or long_jump_access
|
|
|
377 |
is set, most translators would allocate the space for the declaration
|
|
|
378 |
on the main-store stack rather than in an available register. If it
|
|
|
379 |
is not set, then a translator is free to use its own criteria for
|
|
|
380 |
whether space which can fit into a register is allocated on the stack
|
|
|
381 |
or in a register, provided there is no observable difference (other
|
|
|
382 |
than time or program size) between the two possibilities.<P>
|
|
|
383 |
Some of these criteria are rather obvious; for example, if a pointer
|
|
|
384 |
to local variable is passed outside the procedure in an opaque manner,
|
|
|
385 |
then it is highly unlikely that one can allocate the variable in a
|
|
|
386 |
register. Some might be less obvious. If the only uses of a TAG t
|
|
|
387 |
was in obtain_tag(t)s which are operands of contents or the left-hand
|
|
|
388 |
operands of assigns , most ABIs would allow the tag to be placed in
|
|
|
389 |
a register. We do not necessarily have to generate a pointer value
|
|
|
390 |
if it can be subsumed by the operations available.<P>
|
|
|
391 |
<A NAME=S47>
|
|
|
392 |
<H4>5.3.2.2 . Access "hints"</H4>
|
|
|
393 |
A variable tag with ACCESS constant is a write-once value; once it
|
|
|
394 |
is initialised the variable will always contain the initialisation.
|
|
|
395 |
In other words the tag is a pointer to a constant value; translators
|
|
|
396 |
can use this information to apply various optimisations.<P>
|
|
|
397 |
A POINTER tag with ACCESS no_other_read or no_other_write is asserting
|
|
|
398 |
that there are no "aliassed" accesses to the contents of
|
|
|
399 |
the pointer. For example, when applied to a parameter of a procedure,
|
|
|
400 |
it is saying that the original pointer of the tag is distinct from
|
|
|
401 |
any other tags used (reading/writing) in the lifetime of the tag.
|
|
|
402 |
These other tags could either be further parameters of the procedure
|
|
|
403 |
or globals. Clearly, this is useful for describing the limitations
|
|
|
404 |
imposed by Fortran parameters, for example.<P>
|
|
|
405 |
<A NAME=S48>
|
|
|
406 |
<H3>5.3.3. <A NAME=57>current_env, env_offset</H3>
|
|
|
407 |
The constructor current_env gives a pointer to the current procedure
|
|
|
408 |
frame of SHAPE POINTER(<I>fa</I>) where <I>fa</I>
|
|
|
409 |
is depends on how the procedure was defined and will be some set of
|
|
|
410 |
the special frame ALIGNMENTs. This set will always include locals_alignment
|
|
|
411 |
- the alignment of any locals defined within the procedure. If the
|
|
|
412 |
procedure has any caller- parameters, the set will also include callers_alignment(b)
|
|
|
413 |
where b indicates whether there can be a variable number of them;
|
|
|
414 |
similarly for callee-parameters.<P>
|
|
|
415 |
Offsets from the current_env of a procedure to a tag declared in the
|
|
|
416 |
procedure are constructed by env_offset:<P>
|
|
|
417 |
<PRE>
|
|
|
418 |
<I>fa</I>: ALIGNMENT
|
|
|
419 |
<I>y</I>: ALIGNMENT
|
|
|
420 |
<I>t</I>: TAG <I>x</I>
|
|
|
421 |
-> EXP OFFSET(<I>fa</I>,<I>y</I>)
|
|
|
422 |
</PRE>
|
|
|
423 |
The frame ALIGNMENT <I>fa</I> will be the appropriate one for the
|
|
|
424 |
TAG <I>t</I>; i.e. if <I>t</I> is a local then the <I>fa</I> will
|
|
|
425 |
be locals_alignment; if <I>t</I> is a caller parameter, <I>fa</I>
|
|
|
426 |
will be callers_alignment(b); if <I>t</I> is a callee_parameter, <I>fa</I>
|
|
|
427 |
will be callees_alignment(b). The alignment <I>y</I> will be the alignment
|
|
|
428 |
of the initialisation of <I>t</I>.<P>
|
|
|
429 |
The offset arithmetic operations allow one to access the values of
|
|
|
430 |
tags non-locally using values derived from current_env and env_offset.
|
|
|
431 |
They are effectively defined by the following identities:<P>
|
|
|
432 |
<PRE>
|
|
|
433 |
If TAG t is derived from a variable definition
|
|
|
434 |
add_to_ptr(current_env(), env_offset(locals_alignment, A, t)) = obtain_tag(t)
|
|
|
435 |
if TAG t is derived from an identify definition:
|
|
|
436 |
contents(S, add_to_ptr(current_env(), env_offset(locals_alignment, A, t))) = obtain_tag(t)
|
|
|
437 |
if TAG t is derived from a caller parameter:
|
|
|
438 |
add_to_ptr(current_env(), env_offset(callers_alignment(b), A, t)) = obtain_tag(t)
|
|
|
439 |
if TAG t is derived from a callee parameter:
|
|
|
440 |
add_to_ptr(current_env(), env_offset(callees_alignment(b), A, t)) = obtain_tag(t)
|
|
|
441 |
</PRE>
|
|
|
442 |
These identities are valid throughout the extent of t, including in
|
|
|
443 |
inner procedure calls. In other words, one can dynamically create
|
|
|
444 |
a pointer to the value by composing current_env and env_offset. <P>
|
|
|
445 |
The importance of this is that env_offset(t) is a constant OFFSET
|
|
|
446 |
and can be used anywhere within the enclosing UNIT, in other procedures
|
|
|
447 |
or as part of constant TAGDEF; remember that the TDFINT underlying
|
|
|
448 |
t is unique within the UNIT. The result of a current_env could be
|
|
|
449 |
passed to another procedure (as a parameter, say) and this new procedure
|
|
|
450 |
could then access a local of the original by using its env_offset.
|
|
|
451 |
This would be the method one would use to access non-local, non-global
|
|
|
452 |
identifiers in a language which allowed one to define procedures within
|
|
|
453 |
procedures such as Pascal or Algol. Of course, given the stack-based
|
|
|
454 |
model, the value given by current_env becomes meaningless once the
|
|
|
455 |
procedure in which it is invoked is exited.<P>
|
|
|
456 |
<P>
|
|
|
457 |
<A NAME=S49>
|
|
|
458 |
<H3>5.3.4. <A NAME=60>local_alloc, local_free_all, last_local</H3>
|
|
|
459 |
The size of stack frame produced by variable and identify definitions
|
|
|
460 |
is a translate-time constant since the frame is composed of values
|
|
|
461 |
whose SHAPEs are known. TDF also allows one to produce dynamically
|
|
|
462 |
sized local objects which are conceptually part of the frame. These
|
|
|
463 |
are produced by local_alloc:<P>
|
|
|
464 |
<PRE>
|
|
|
465 |
<I> arg1</I>: EXP OFFSET(<I>x, y</I>)
|
|
|
466 |
-> EXP POINTER(alloca_alignment)
|
|
|
467 |
</PRE>
|
|
|
468 |
The operand <I>arg1</I> gives the size of the new object required
|
|
|
469 |
and the result is a pointer to the space for this object "on
|
|
|
470 |
top of the stack" as part of the frame. The quotation marks indicate
|
|
|
471 |
that a translator writer might prefer to maintain a dynamic stack
|
|
|
472 |
as well as static one. There are some disadvantages in putting everything
|
|
|
473 |
into one stack which may well out-weigh the trouble of maintaining
|
|
|
474 |
another stack which is relatively infrequently used. If a frame has
|
|
|
475 |
a known size, then all addressing of locals can be done using a stack-front
|
|
|
476 |
register; if it is dynamically sized, then another frame-pointer register
|
|
|
477 |
must be used - some ABIs make this easy but not all. The majority
|
|
|
478 |
of procedures contain no local_allocs, so their addressing of locals
|
|
|
479 |
can always be done relative to a stack-front; only the others have
|
|
|
480 |
to use another register for a frame pointer.<P>
|
|
|
481 |
The alignment of pointer result is alloca_alignment which must include
|
|
|
482 |
all SHAPE alignments.<P>
|
|
|
483 |
There are two constructors for releasing space generated by local_alloc.
|
|
|
484 |
To release all such space generated in the current procedure one does
|
|
|
485 |
local_free_all(); this reduces the size of the current frame to its
|
|
|
486 |
static size. <P>
|
|
|
487 |
The other constructor is local_free whch is effectively a "pop"
|
|
|
488 |
to local_alloc's "push":<P>
|
|
|
489 |
<PRE>
|
|
|
490 |
a: EXP OFFSET(<I>x</I>, <I>y</I>)
|
|
|
491 |
<I> p</I>: EXP POINTER(alloca_alignment)
|
|
|
492 |
-> EXP TOP
|
|
|
493 |
</PRE>
|
|
|
494 |
Here <I>p</I> must evaluate to a pointer generated either by local_alloc
|
|
|
495 |
or last_local . The effect is to free all of the space locally allocated
|
|
|
496 |
after p. The usual implementation (with a downward growing stack)
|
|
|
497 |
of this is that p becomes the "top of stack" pointer<P>
|
|
|
498 |
The use of a procedure with an untidy_return is just a generalisation
|
|
|
499 |
of the idea of local_alloc and the space made available by its use
|
|
|
500 |
can be freed in the same way as normal local allocations. Of course,
|
|
|
501 |
given that it could be the result of the procedure it can be structured
|
|
|
502 |
in an arbitrarily complicated way.<P>
|
|
|
503 |
<A NAME=S50>
|
|
|
504 |
<HR><H2>5.4. Heap storage</H2>
|
|
|
505 |
At the moment, there are no explicit constructors of creating dynamic
|
|
|
506 |
off-stack storage in TDF. Any off-stack storage requirements must
|
|
|
507 |
be met by the API in which the system is embedded, using the standard
|
|
|
508 |
procedural interface. For example, the ANSI C API allows the creation
|
|
|
509 |
of heap space using standard library procedures like malloc.<P>
|
|
|
510 |
<HR>
|
|
|
511 |
<P><I>Part of the <A HREF="../index.html">TenDRA Web</A>.<BR>Crown
|
|
|
512 |
Copyright © 1998.</I></P>
|
|
|
513 |
</BODY>
|
|
|
514 |
</HTML>
|