Subversion Repositories tendra.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
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 &quot;hints&quot; 
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
		   -&gt; 	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
		   -&gt; 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
		   -&gt; 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
	--&gt; 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
		   -&gt; 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
		   -&gt; 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
		   -&gt; 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
		   -&gt; 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
		   -&gt; 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
		   -&gt; 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
&quot;hints&quot; 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 &quot;hints&quot;</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 &quot;aliassed&quot; 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
		   -&gt; 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
		   -&gt; 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 &quot;on
470
top of the stack&quot; 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 &quot;pop&quot;
488
to local_alloc's &quot;push&quot;:<P>
489
<PRE>
490
	a:	EXP OFFSET(<I>x</I>, <I>y</I>)
491
<I>	p</I>:	 EXP POINTER(alloca_alignment)
492
		   -&gt; 	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 &quot;top of stack&quot; 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 &copy; 1998.</I></P>
513
</BODY>
514
</HTML>