2 % (c) The GRASP/AQUA Project, Glasgow University, 1992-1996
4 \section[CgHeapery]{Heap management functions}
7 #include "HsVersions.h"
11 allocHeap, allocDynClosure
13 -- new functions, basically inserting macro calls into Code -- HWL
14 , heapCheckOnly, fetchAndReschedule, yield
22 import AbsCUtils ( mkAbstractCs, getAmodeRep )
23 import CgRetConv ( mkLiveRegsMask )
24 import CgUsages ( getVirtAndRealHp, setVirtHp, setRealHp,
27 import ClosureInfo ( closureSize, closureHdrSize, closureGoodStuffSize,
28 slopSize, allocProfilingMsg, closureKind
30 import HeapOffs ( isZeroOff, addOff, intOff,
33 import PrimRep ( PrimRep(..) )
36 %************************************************************************
38 \subsection[CgHeapery-heap-overflow]{Heap overflow checking}
40 %************************************************************************
42 The new code for heapChecks. For GrAnSim the code for doing a heap check
43 and doing a context switch has been separated. Especially, the HEAP_CHK
44 macro only performs a heap check. THREAD_CONTEXT_SWITCH should be used for
45 doing a context switch. GRAN_FETCH_AND_RESCHEDULE must be put at the
46 beginning of every slow entry code in order to simulate the fetching of
47 closures. If fetching is necessary (i.e. current closure is not local) then
48 an automatic context switch is done.
51 heapCheck :: [MagicId] -- Live registers
52 -> Bool -- Node reqd after GC?
56 heapCheck = heapCheck' False
58 heapCheckOnly :: [MagicId] -- Live registers
59 -> Bool -- Node reqd after GC?
63 heapCheckOnly = heapCheck' False
65 -- May be emit context switch and emit heap check macro
67 heapCheck' :: Bool -- context switch here?
68 -> [MagicId] -- Live registers
69 -> Bool -- Node reqd after GC?
73 heapCheck' do_context_switch regs node_reqd code
74 = initHeapUsage (\ hHw -> do_heap_chk hHw `thenC` code)
77 do_heap_chk :: HeapOffset -> Code
78 do_heap_chk words_required
80 -- HWL:: absC (CComment "Forced heap check --- HWL") `thenC`
81 --absC (if do_context_switch
82 -- then context_switch_code
83 -- else AbsCNop) `thenC`
85 absC (if do_context_switch && not (isZeroOff words_required)
86 then context_switch_code
88 absC (if isZeroOff(words_required)
90 else checking_code) `thenC`
93 -- For GrAnSim we want heap checks even if no heap is allocated in
94 -- the basic block to make context switches possible.
95 -- So, the if construct has been replaced by its else branch.
97 -- The test is *inside* the absC, to avoid black holes!
99 -- Now we have set up the real heap pointer and checked there is
100 -- enough space. It remains only to reflect this in the environment
102 setRealHp words_required
104 -- The "word_required" here is a fudge.
105 -- *** IT DEPENDS ON THE DIRECTION ***, and on
106 -- whether the Hp is moved the whole way all
109 all_regs = if node_reqd then node:regs else regs
110 liveness_mask = mkLiveRegsMask all_regs
112 maybe_context_switch = if do_context_switch
113 then context_switch_code
116 context_switch_code = CMacroStmt THREAD_CONTEXT_SWITCH [
117 mkIntCLit liveness_mask,
118 mkIntCLit (if node_reqd then 1 else 0)]
120 -- Good old heap check (excluding context switch)
121 checking_code = CMacroStmt HEAP_CHK [
122 mkIntCLit liveness_mask,
123 COffset words_required,
124 mkIntCLit (if node_reqd then 1 else 0)]
126 -- Emit macro for simulating a fetch and then reschedule
128 fetchAndReschedule :: [MagicId] -- Live registers
129 -> Bool -- Node reqd?
132 fetchAndReschedule regs node_reqd =
133 if (node `elem` regs || node_reqd)
134 then fetch_code `thenC` reschedule_code
137 all_regs = if node_reqd then node:regs else regs
138 liveness_mask = mkLiveRegsMask all_regs
140 reschedule_code = absC (CMacroStmt GRAN_RESCHEDULE [
141 mkIntCLit liveness_mask,
142 mkIntCLit (if node_reqd then 1 else 0)])
144 --HWL: generate GRAN_FETCH macro for GrAnSim
145 -- currently GRAN_FETCH and GRAN_FETCH_AND_RESCHEDULE are miai
146 fetch_code = absC (CMacroStmt GRAN_FETCH [])
149 The @GRAN_YIELD@ macro is taken from JSM's code for Concurrent Haskell. It
150 allows to context-switch at places where @node@ is not alive (it uses the
151 @Continue@ rather than the @EnterNodeCode@ function in the RTS). We emit
152 this kind of macro at the beginning of the following kinds of basic bocks:
154 \item Slow entry code where node is not alive (see @CgClosure.lhs@). Normally
155 we use @fetchAndReschedule@ at a slow entry code.
156 \item Fast entry code (see @CgClosure.lhs@).
157 \item Alternatives in case expressions (@CLabelledCode@ structures), provided
158 that they are not inlined (see @CgCases.lhs@). These alternatives will
159 be turned into separate functions.
163 yield :: [MagicId] -- Live registers
164 -> Bool -- Node reqd?
167 yield regs node_reqd =
168 -- NB: node is not alive; that's why we use DO_YIELD rather than
172 all_regs = if node_reqd then node:regs else regs
173 liveness_mask = mkLiveRegsMask all_regs
175 yield_code = absC (CMacroStmt GRAN_YIELD [mkIntCLit liveness_mask])
178 %************************************************************************
180 \subsection[initClosure]{Initialise a dynamic closure}
182 %************************************************************************
184 @allocDynClosure@ puts the thing in the heap, and modifies the virtual Hp
190 -> CAddrMode -- Cost Centre to stick in the object
191 -> CAddrMode -- Cost Centre to blame for this alloc
192 -- (usually the same; sometimes "OVERHEAD")
194 -> [(CAddrMode, VirtualHeapOffset)] -- Offsets from start of the object
195 -- ie Info ptr has offset zero.
196 -> FCode VirtualHeapOffset -- Returns virt offset of object
198 allocDynClosure closure_info use_cc blame_cc amodes_with_offsets
199 = getVirtAndRealHp `thenFC` \ (virtHp, realHp) ->
201 -- FIND THE OFFSET OF THE INFO-PTR WORD
202 -- virtHp points to last allocated word, ie 1 *before* the
203 -- info-ptr word of new object.
204 let info_offset = addOff virtHp (intOff 1)
206 -- do_move IS THE ASSIGNMENT FUNCTION
207 do_move (amode, offset_from_start)
208 = CAssign (CVal (HpRel realHp
209 (info_offset `addOff` offset_from_start))
213 -- SAY WHAT WE ARE ABOUT TO DO
214 profCtrC (allocProfilingMsg closure_info)
215 [COffset (closureHdrSize closure_info),
216 mkIntCLit (closureGoodStuffSize closure_info),
218 COffset closure_size] `thenC`
221 absC ( mkAbstractCs (
222 [ CInitHdr closure_info (HpRel realHp info_offset) use_cc False ]
223 ++ (map do_move amodes_with_offsets))) `thenC`
225 -- GENERATE CC PROFILING MESSAGES
226 costCentresC SLIT("CC_ALLOC") [blame_cc,
227 COffset closure_size,
228 CLitLit (_PK_ (closureKind closure_info)) IntRep]
231 -- BUMP THE VIRTUAL HEAP POINTER
232 setVirtHp (virtHp `addOff` closure_size) `thenC`
234 -- RETURN PTR TO START OF OBJECT
237 closure_size = closureSize closure_info
238 slop_size = slopSize closure_info
241 %************************************************************************
243 \subsection{Allocate uninitialized heap space}
245 %************************************************************************
248 allocHeap :: HeapOffset -- Size of the space required
249 -> FCode CAddrMode -- Addr mode for first word of object
252 = getVirtAndRealHp `thenFC` \ (virtHp, realHp) ->
253 let block_start = addOff virtHp (intOff 1)
255 -- We charge the allocation to "PRIM" (which is probably right)
256 profCtrC SLIT("ALLOC_PRIM2") [COffset space] `thenC`
258 -- BUMP THE VIRTUAL HEAP POINTER
259 setVirtHp (virtHp `addOff` space) `thenC`
261 -- RETURN PTR TO START OF OBJECT
262 returnFC (CAddr (HpRel realHp block_start))