The environment of the computation Declarations introduce names that denote entities. At execution-time, entities are bound to values or to locations: name value (functional) name location value (imperative) Value binding.
Download
Report
Transcript The environment of the computation Declarations introduce names that denote entities. At execution-time, entities are bound to values or to locations: name value (functional) name location value (imperative) Value binding.
The environment of the
computation
Declarations introduce names that denote entities.
At execution-time, entities are bound to values or to locations:
name
value
(functional)
name
location
value (imperative)
Value binding takes place during function invocation
Names are bound to memory locations on scope entry. Locations
are bound to values by assignment.
Compiler establishes symbolic mapping between names and
locations: name
offset from run-time pointer
Run-time pointer is stack frame, TOC entry, static link, etc.
Run-time organization
Each subprogram invocation creates an activation record.
Recursion imposes stack allocation (all languages today)
Activation record hold actuals, linkage information, saved registers,
local entities.
caller: place actuals on stack, return address, linkage information,
then transfer control to callee.
Prologue: save registers, allocate space for locals
Epilogue: place return value in register or stack position, update
actuals, restore registers, then transfer control to caller.
Binding of locations: actuals and locals are at fixed offsets from
frame pointers
complications: variable no. of actuals, dynamic objects.
Activation record layout
actual
actual
Frame pointer
Handled by caller
Return addr
Save area
local
local
Stack pointer
Handled by callee
Save area
Linkage information:
Control link: previous value of frame pointer
Static link: address of stack frame of lexical parent
Return address: in caller
Other saved registers.
Compiler emits prologue code to save frame
pointer, increment stack pointer, save registers.
Stack (sp) := fp; -- save frame pointer after actuals
fp := sp;
-- new frame starts here
Functions with variable
number of parameters
printf (“this is %d a format %d string”, x, y);
within body of printf, need to locate as many actuals as place-holders in
the format string.
Solution: place parameters on stack in reverse order. Actuals at
positive offset from FP, locals at negative offset from FP.
actual n
actual n-1
…
actual 1 (format string)
return address
Objects of dynamic size
declare
x : string (1..N); -- N global, non-constant
y : string (1..N);
begin...
where is the start of y in the activation record?
Solution 1: use indirection: activation record hold pointers. Simpler
implementation, costly dynamic allocation., deallocation.
solution 2:: local indirection: activation record holds offset into stack.
Faster allocation/deallocation, complex implementation.
Run-time access to globals
procedure outer is
global : integer;
procedure inner is
local : integer;
begin
...
if global = local then
-- recursive
-- recursive
-- how do we locate global?
Need run-time structure to locate activation record of statically
enclosing scopes. Environment includes current activation record
AND activation records of parent scopes.
Global linkage
Static chain: pointer to activation record of statically enclosing
scope
Display:: array of pointers to activation records
Neither works for function values (higher-order functions)
functional languages allocate activation records on heap
may not work for pointers to functions
simpler if there is no nesting (C, C++, Java)
can check static legality in many cases (Ada)
Static Links
Activation record hold pointer to activation record of enclosing
scope. Setup as part of call prologue.
To retrieve
entity 3
frames out: 3
dereference
operations
To enclosing scope
outer
outer
outer
inner
inner
inner
inner
Display
Global array of pointers to current activation records
outermost
display
...
outer
outer
outer
inner
inner
inner
inner
To retrieve
entity 3
frames out:
one indexing
operation
Subprogram parameters
type proc is access procedure (X : Integer);
procedure Perform (Helper : proc) is
begin
… proc (42);
end;
procedure Action (X : Integer) is …
procedure Proxy is
begin
Perform (Action’Access);
end;
Proxy can see (and call) Action, therefore environment of Action ( e.g static link) Is
known to Proxy. Proxy transmits to Perform both a pointer to the code for Action, and
the proper static link for it.
-- ‘Access creates pair
(ptr to Action , environment of Action)
simplest implementation if Env is pointer (static link) but can also be
display: more efficient to retrieve non-local entities, less efficient for
subprogram parameters, because display is array of variable size.
Functions as first-class values force
heap allocation of activation record
The environment of definition of the function must be preserved
until the point of call: activation record cannot be reclaimed if it
creates functions.
Functional languages require more complex run-time
management.
Higher-order functions: functions that return (build) functions, are
powerful but complex mechanisms. Imperative languages restrict
their use.
A function that returns a pointer to a function is a higher-order
function.
Higher-order functions
Both arguments and result can be (pointers to) subprograms:
type Func is access function (x : integer) return integer;
function compose (first, second : Func) return Func is
begin
function result (x : integer) return integer is
begin
return (second (first (x)); -- implicit dereference on call
end;
-- in C++ as well.
begin
return result ’access; -- but first and second won’t exist at the point
end;
-- of call, so illegal in Ada.
Restricting higher-order functions
C: no nested definitions, so environment is always global.
C++: ditto, except for nested classes.
Ada: static checks to reject possible dangling references
Modula: pointers to function illegal if function not declared at toplevel.
LISP: special syntax to indicate capture of environment
ML, Haskell: no restriction: compose is a primitive
Returning composite values
Intermediate problem: functions that return values of non-static
sizes:
function conc3 (x, y, z : string) return string is
begin
return x & “:” & y & “:” & z;
end;
example : string := conc3 (this, that, theother);
best not to use heap, but still need indirection.
Simplest : forbid it (Pascal, C) or use heap automatically (Java)
More efficient: local allocate/free on special stack.
Historical (algol68): two stacks.
Storage management
Data local to functions: stack
Global data: static areas
Class information, static members
Packages
Fortran common blocks
Linker establishes array of pointers to static areas
(TOC).
Dynamic data: heap
Garbage collection
Run-time system manages heap, maintains free list
Allocation by first-fit or best-fit (variants with buddy
system, etc).
Garbage collector must be able to distinguish data that is
live from unreachable data.
Garbage collector attaches unreachable data (garbage)
to free list.
Garbage collector may compact data in use, to improve
program locality
Marking live data
Data is live if it can be referenced from any active function
Garbage collector must have run-time information on data layout:
Pointer data in activation records
Pointer data in data structures
Marking is a graph traversal starting from roots: pointers in the
stack.
User cannot have control over pointer manipulation:
Languages with garbage collection do not have explicit pointers.
Sweeping and compacting garbage
Linear pass over the heap: all unmarked data is
unreachable, and can be chained onto the free list
For compaction, rewrite live data contiguously, so that
free space is also contiguous
Additional pass to adjust pointers: need to compute
destination address of each block, and modify all
pointers into that block. Needs inverse graph: each block
has a chain of references to itself.
After pointers are adjusted, each block is copied to its
destination.