1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
|
%
% (c) The AQUA Project, Glasgow University, 1993-1998
%
\begin{code}
module StixMacro ( macroCode, checkCode ) where
#include "HsVersions.h"
#include "nativeGen/NCG.h"
import {-# SOURCE #-} StixPrim ( amodeToStix )
import MachRegs
import AbsCSyn ( CStmtMacro(..), CAddrMode, tagreg, CCheckMacro(..) )
import SMRep ( fixedHdrSize )
import Constants ( uF_RET, uF_UPDATEE, uF_SIZE )
import ForeignCall ( CCallConv(..) )
import MachOp ( MachOp(..) )
import PrimRep ( PrimRep(..) )
import Stix
import Panic ( panic )
import UniqSupply ( returnUs, thenUs, UniqSM )
import CLabel ( mkBlackHoleInfoTableLabel, mkIndStaticInfoLabel,
mkBlackHoleBQInfoTableLabel,
mkIndInfoLabel, mkUpdInfoLabel, mkRtsGCEntryLabel )
\end{code}
--------------------------------------------------------------------------------
The @ARGS_CHK_A{_LOAD_NODE}@ macros check for sufficient arguments on
the A stack, and perform a tail call to @UpdatePAP@ if the arguments are
not there. The @_LOAD_NODE@ version also loads R1 with an appropriate
closure address.
\begin{code}
macroCode
:: CStmtMacro -- statement macro
-> [StixExpr] -- args
-> UniqSM StixStmtList
\end{code}
-----------------------------------------------------------------------------
Updating a CAF
@UPD_CAF@ involves changing the info pointer of the closure, and
adding an indirection.
\begin{code}
macroCode UPD_CAF [cafptr,bhptr]
= let
new_caf = StVoidable (StCall (Left FSLIT("newCAF")) CCallConv VoidRep [cafptr])
a1 = StAssignMem PtrRep (StIndex PtrRep cafptr fixedHS) bhptr
a2 = StAssignMem PtrRep cafptr ind_static_info
in
returnUs (\xs -> new_caf : a1 : a2 : xs)
\end{code}
-----------------------------------------------------------------------------
Blackholing
We do lazy blackholing: no need to overwrite thunks with blackholes
the minute they're entered, as long as we do it before a context
switch or garbage collection, that's ok.
Don't blackhole single entry closures, for the following reasons:
- if the compiler has decided that they won't be entered again,
that probably means that nothing has a pointer to it
(not necessarily true, but...)
- no need to blackhole for concurrency reasons, because nothing
can block on the result of this computation.
\begin{code}
macroCode UPD_BH_UPDATABLE args = returnUs id
macroCode UPD_BH_SINGLE_ENTRY args = returnUs id
{-
= let
update = StAssign PtrRep (StInd PtrRep arg) bh_info
in
returnUs (\xs -> update : xs)
-}
\end{code}
-----------------------------------------------------------------------------
Update frames
Push an update frame on the stack.
\begin{code}
macroCode PUSH_UPD_FRAME [bhptr, _{-0-}]
= let
frame n = StIndex PtrRep (StReg stgSp) (StInt (toInteger (n-uF_SIZE)))
-- HWL: these values are *wrong* in a GranSim setup; ToDo: fix
a1 = StAssignMem PtrRep (frame uF_RET) upd_frame_info
a4 = StAssignMem PtrRep (frame uF_UPDATEE) bhptr
in
returnUs (\xs -> a1 : a4 : xs)
\end{code}
-----------------------------------------------------------------------------
Setting the tag register
This one only applies if we have a machine register devoted to TagReg.
\begin{code}
macroCode SET_TAG [tag]
= case get_MagicId_reg_or_addr tagreg of
Right baseRegAddr
-> returnUs id
Left realreg
-> let a1 = StAssignReg IntRep (StixMagicId tagreg) tag
in returnUs ( \xs -> a1 : xs )
\end{code}
-----------------------------------------------------------------------------
\begin{code}
macroCode REGISTER_IMPORT [arg]
= returnUs (
\xs -> StAssignMem WordRep (StReg stgSp) arg
: StAssignReg PtrRep stgSp (StMachOp MO_Nat_Add [StReg stgSp, StInt 4])
: xs
)
macroCode REGISTER_FOREIGN_EXPORT [arg]
= returnUs (
\xs -> StVoidable (
StCall (Left FSLIT("getStablePtr")) CCallConv VoidRep
[arg]
)
: xs
)
macroCode other args
= panic "StixMacro.macroCode"
\end{code}
Do the business for a @HEAP_CHK@, having converted the args to Trees
of StixOp.
-----------------------------------------------------------------------------
Let's make sure that these CAFs are lifted out, shall we?
\begin{code}
-- Some common labels
bh_info, ind_static_info, ind_info :: StixExpr
bh_info = StCLbl mkBlackHoleInfoTableLabel
bq_info = StCLbl mkBlackHoleBQInfoTableLabel
ind_static_info = StCLbl mkIndStaticInfoLabel
ind_info = StCLbl mkIndInfoLabel
upd_frame_info = StCLbl mkUpdInfoLabel
-- Some common call trees
\end{code}
-----------------------------------------------------------------------------
Heap/Stack checks
\begin{code}
checkCode :: CCheckMacro -> [CAddrMode] -> StixStmtList -> UniqSM StixStmtList
checkCode macro args assts
= getUniqLabelNCG `thenUs` \ ulbl_fail ->
getUniqLabelNCG `thenUs` \ ulbl_pass ->
let args_stix = map amodeToStix args
newHp wds = StIndex PtrRep (StReg stgHp) wds
assign_hp wds = StAssignReg PtrRep stgHp (newHp wds)
hp_alloc wds = StAssignReg IntRep stgHpAlloc wds
test_hp = StMachOp MO_NatU_Le [StReg stgHp, StReg stgHpLim]
cjmp_hp = StCondJump ulbl_pass test_hp
newSp wds = StIndex PtrRep (StReg stgSp) (StMachOp MO_NatS_Neg [wds])
test_sp_pass wds = StMachOp MO_NatU_Ge [newSp wds, StReg stgSpLim]
test_sp_fail wds = StMachOp MO_NatU_Lt [newSp wds, StReg stgSpLim]
cjmp_sp_pass wds = StCondJump ulbl_pass (test_sp_pass wds)
cjmp_sp_fail wds = StCondJump ulbl_fail (test_sp_fail wds)
assign_ret r ret = mkStAssign CodePtrRep r ret
fail = StLabel ulbl_fail
join = StLabel ulbl_pass
-- see includes/StgMacros.h for explaination of these magic consts
aLL_NON_PTRS = 0xff
assign_liveness ptr_regs
= StAssignReg WordRep stgR9
(StMachOp MO_Nat_Xor [StInt aLL_NON_PTRS, ptr_regs])
assign_reentry reentry
= StAssignReg WordRep stgR10 reentry
in
returnUs (
case macro of
HP_CHK_NP ->
let [words] = args_stix
in (\xs -> assign_hp words : cjmp_hp :
assts (hp_alloc words : gc_enter : join : xs))
STK_CHK_NP ->
let [words] = args_stix
in (\xs -> cjmp_sp_pass words :
assts (gc_enter : join : xs))
HP_STK_CHK_NP ->
let [sp_words,hp_words] = args_stix
in (\xs -> cjmp_sp_fail sp_words :
assign_hp hp_words : cjmp_hp :
fail :
assts (hp_alloc hp_words : gc_enter
: join : xs))
HP_CHK_FUN ->
let [words] = args_stix
in (\xs -> assign_hp words : cjmp_hp :
assts (hp_alloc words : gc_fun : join : xs))
STK_CHK_FUN ->
let [words] = args_stix
in (\xs -> cjmp_sp_pass words :
assts (gc_fun : join : xs))
HP_STK_CHK_FUN ->
let [sp_words,hp_words] = args_stix
in (\xs -> cjmp_sp_fail sp_words :
assign_hp hp_words : cjmp_hp :
fail :
assts (hp_alloc hp_words
: gc_fun : join : xs))
HP_CHK_NOREGS ->
let [words] = args_stix
in (\xs -> assign_hp words : cjmp_hp :
assts (hp_alloc words : gc_noregs : join : xs))
HP_CHK_UNPT_R1 ->
let [words] = args_stix
in (\xs -> assign_hp words : cjmp_hp :
assts (hp_alloc words : gc_unpt_r1 : join : xs))
HP_CHK_UNBX_R1 ->
let [words] = args_stix
in (\xs -> assign_hp words : cjmp_hp :
assts (hp_alloc words : gc_unbx_r1 : join : xs))
HP_CHK_F1 ->
let [words] = args_stix
in (\xs -> assign_hp words : cjmp_hp :
assts (hp_alloc words : gc_f1 : join : xs))
HP_CHK_D1 ->
let [words] = args_stix
in (\xs -> assign_hp words : cjmp_hp :
assts (hp_alloc words : gc_d1 : join : xs))
HP_CHK_L1 ->
let [words] = args_stix
in (\xs -> assign_hp words : cjmp_hp :
assts (hp_alloc words : gc_l1 : join : xs))
HP_CHK_UNBX_TUPLE ->
let [words,liveness] = args_stix
in (\xs -> assign_hp words : cjmp_hp :
assts (hp_alloc words : assign_liveness liveness :
gc_ut : join : xs))
)
-- Various canned heap-check routines
mkStJump_to_GCentry_name :: String -> StixStmt
mkStJump_to_GCentry_name gcname
-- | opt_Static
= StJump NoDestInfo (StCLbl (mkRtsGCEntryLabel gcname))
-- | otherwise -- it's in a different DLL
-- = StJump (StInd PtrRep (StLitLbl True sdoc))
mkStJump_to_RegTable_offw :: Int -> StixStmt
mkStJump_to_RegTable_offw regtable_offw
-- | opt_Static
= StJump NoDestInfo (StInd PtrRep (get_Regtable_addr_from_offset regtable_offw))
-- | otherwise
-- do something plausible for cross-DLL jump
gc_enter = mkStJump_to_RegTable_offw OFFSET_stgGCEnter1
gc_fun = mkStJump_to_RegTable_offw OFFSET_stgGCFun
gc_noregs = mkStJump_to_GCentry_name "stg_gc_noregs"
gc_unpt_r1 = mkStJump_to_GCentry_name "stg_gc_unpt_r1"
gc_unbx_r1 = mkStJump_to_GCentry_name "stg_gc_unbx_r1"
gc_f1 = mkStJump_to_GCentry_name "stg_gc_f1"
gc_d1 = mkStJump_to_GCentry_name "stg_gc_d1"
gc_l1 = mkStJump_to_GCentry_name "stg_gc_l1"
gc_ut = mkStJump_to_GCentry_name "stg_gc_ut"
\end{code}
|