1 {-# LANGUAGE BangPatterns, CPP, MagicHash, RecordWildCards #-}
2 {-# OPTIONS_GHC -optc-DNON_POSIX_SOURCE #-}
4 -- (c) The University of Glasgow 2002-2006
7 -- | ByteCodeLink: Bytecode assembler and linker
9 assembleBCOs
, assembleOneBCO
,
12 SizedSeq
, sizeSS
, ssElts
,
13 iNTERP_STACK_CHECK_THRESH
16 #include
"HsVersions.h"
23 import GHCi
.RemoteTypes
32 import StgCmmLayout
( ArgRep
(..) )
45 import Control
.Monad
.ST
( runST
)
46 import Control
.Monad
.Trans
.Class
47 import Control
.Monad
.Trans
.State
.Strict
49 import Data
.Array.MArray
51 import qualified Data
.Array.Unboxed
as Array
52 import Data
.Array.Base
( UArray
(..) )
54 import Data
.Array.Unsafe
( castSTUArray
)
57 import Data
.Char ( ord )
60 import Data
.Maybe (fromMaybe)
61 import qualified Data
.Map
as Map
63 -- -----------------------------------------------------------------------------
66 -- CompiledByteCode represents the result of byte-code
67 -- compiling a bunch of functions and data types
69 -- | Finds external references. Remember to remove the names
70 -- defined by this group of BCOs themselves
71 bcoFreeNames
:: UnlinkedBCO
-> UniqDSet Name
73 = bco_refs bco `uniqDSetMinusUniqSet` mkNameSet
[unlinkedBCOName bco
]
75 bco_refs
(UnlinkedBCO _ _ _ _ nonptrs ptrs
)
76 = unionManyUniqDSets
(
77 mkUniqDSet
[ n | BCOPtrName n
<- ssElts ptrs
] :
78 mkUniqDSet
[ n | BCONPtrItbl n
<- ssElts nonptrs
] :
79 map bco_refs
[ bco | BCOPtrBCO bco
<- ssElts ptrs
]
82 -- -----------------------------------------------------------------------------
83 -- The bytecode assembler
85 -- The object format for bytecodes is: 16 bits for the opcode, and 16
86 -- for each field -- so the code can be considered a sequence of
87 -- 16-bit ints. Each field denotes either a stack offset or number of
88 -- items on the stack (eg SLIDE), and index into the pointer table (eg
89 -- PUSH_G), an index into the literal table (eg PUSH_I/D/L), or a
90 -- bytecode address in this BCO.
92 -- Top level assembler fn.
94 :: HscEnv
-> [ProtoBCO Name
] -> [TyCon
] -> [RemotePtr
()]
96 -> IO CompiledByteCode
97 assembleBCOs hsc_env proto_bcos tycons top_strs modbreaks
= do
98 itblenv
<- mkITbls hsc_env tycons
99 bcos
<- mapM (assembleBCO
(hsc_dflags hsc_env
)) proto_bcos
100 (bcos
',ptrs
) <- mallocStrings hsc_env bcos
101 return CompiledByteCode
104 , bc_ffis
= concat (map protoBCOFFIs proto_bcos
)
105 , bc_strs
= top_strs
++ ptrs
106 , bc_breaks
= modbreaks
109 -- Find all the literal strings and malloc them together. We want to
112 -- a) It should be done when we compile the module, not each time we relink it
113 -- b) For -fexternal-interpreter It's more efficient to malloc the strings
114 -- as a single batch message, especially when compiling in parallel.
116 mallocStrings
:: HscEnv
-> [UnlinkedBCO
] -> IO ([UnlinkedBCO
], [RemotePtr
()])
117 mallocStrings hsc_env ulbcos
= do
118 let bytestrings
= reverse (execState
(mapM_ collect ulbcos
) [])
119 ptrs
<- iservCmd hsc_env
(MallocStrings bytestrings
)
120 return (evalState
(mapM splice ulbcos
) ptrs
, ptrs
)
122 splice bco
@UnlinkedBCO
{..} = do
123 lits
<- mapM spliceLit unlinkedBCOLits
124 ptrs
<- mapM splicePtr unlinkedBCOPtrs
125 return bco
{ unlinkedBCOLits
= lits
, unlinkedBCOPtrs
= ptrs
}
127 spliceLit
(BCONPtrStr _
) = do
128 (RemotePtr p
: rest
) <- get
130 return (BCONPtrWord
(fromIntegral p
))
131 spliceLit other
= return other
133 splicePtr
(BCOPtrBCO bco
) = BCOPtrBCO
<$> splice bco
134 splicePtr other
= return other
136 collect UnlinkedBCO
{..} = do
137 mapM_ collectLit unlinkedBCOLits
138 mapM_ collectPtr unlinkedBCOPtrs
140 collectLit
(BCONPtrStr bs
) = do
143 collectLit _
= return ()
145 collectPtr
(BCOPtrBCO bco
) = collect bco
146 collectPtr _
= return ()
149 assembleOneBCO
:: HscEnv
-> ProtoBCO Name
-> IO UnlinkedBCO
150 assembleOneBCO hsc_env pbco
= do
151 ubco
<- assembleBCO
(hsc_dflags hsc_env
) pbco
152 ([ubco
'], _ptrs
) <- mallocStrings hsc_env
[ubco
]
155 assembleBCO
:: DynFlags
-> ProtoBCO Name
-> IO UnlinkedBCO
156 assembleBCO dflags
(ProtoBCO nm instrs bitmap bsize arity _origin _malloced
) = do
157 -- pass 1: collect up the offsets of the local labels.
158 let asm
= mapM_ (assembleI dflags
) instrs
162 -- Jump instructions are variable-sized, there are long and short variants
163 -- depending on the magnitude of the offset. However, we can't tell what
164 -- size instructions we will need until we have calculated the offsets of
165 -- the labels, which depends on the size of the instructions... So we
166 -- first create the label environment assuming that all jumps are short,
167 -- and if the final size is indeed small enough for short jumps, we are
168 -- done. Otherwise, we repeat the calculation, and we force all jumps in
169 -- this BCO to be long.
170 (n_insns0
, lbl_map0
) = inspectAsm dflags
False initial_offset asm
171 ((n_insns
, lbl_map
), long_jumps
)
172 | isLarge n_insns0
= (inspectAsm dflags
True initial_offset asm
, True)
173 |
otherwise = ((n_insns0
, lbl_map0
), False)
175 env
:: Word16
-> Word
177 (pprPanic
"assembleBCO.findLabel" (ppr lbl
))
178 (Map
.lookup lbl lbl_map
)
180 -- pass 2: run assembler and generate instructions, literals and pointers
181 let initial_state
= (emptySS
, emptySS
, emptySS
)
182 (final_insns
, final_lits
, final_ptrs
) <- flip execStateT initial_state
$ runAsm dflags long_jumps env asm
184 -- precomputed size should be equal to final size
185 ASSERT
(n_insns
== sizeSS final_insns
) return ()
187 let asm_insns
= ssElts final_insns
188 insns_arr
= Array.listArray (0, fromIntegral n_insns
- 1) asm_insns
189 bitmap_arr
= mkBitmapArray bsize bitmap
190 ul_bco
= UnlinkedBCO nm arity insns_arr bitmap_arr final_lits final_ptrs
192 -- 8 Aug 01: Finalisers aren't safe when attached to non-primitive
193 -- objects, since they might get run too early. Disable this until
194 -- we figure out what to do.
195 -- when (notNull malloced) (addFinalizer ul_bco (mapM_ zonk malloced))
199 mkBitmapArray
:: Word16
-> [StgWord
] -> UArray
Int Word64
200 -- Here the return type must be an array of Words, not StgWords,
201 -- because the underlying ByteArray# will end up as a component
203 mkBitmapArray bsize bitmap
204 = Array.listArray (0, length bitmap
) $
205 fromIntegral bsize
: map (fromInteger . fromStgWord
) bitmap
207 -- instrs nonptrs ptrs
208 type AsmState
= (SizedSeq Word16
,
216 -- (unused) | LargeOp Word
219 = AllocPtr
(IO BCOPtr
) (Word
-> Assembler a
)
220 | AllocLit
[BCONPtr
] (Word
-> Assembler a
)
221 | AllocLabel Word16
(Assembler a
)
222 | Emit Word16
[Operand
] (Assembler a
)
225 instance Functor Assembler
where
228 instance Applicative Assembler
where
232 instance Monad Assembler
where
233 NullAsm x
>>= f
= f x
234 AllocPtr p k
>>= f
= AllocPtr p
(k
>=> f
)
235 AllocLit l k
>>= f
= AllocLit l
(k
>=> f
)
236 AllocLabel lbl k
>>= f
= AllocLabel lbl
(k
>>= f
)
237 Emit w ops k
>>= f
= Emit w ops
(k
>>= f
)
239 ioptr
:: IO BCOPtr
-> Assembler Word
240 ioptr p
= AllocPtr p
return
242 ptr
:: BCOPtr
-> Assembler Word
245 lit
:: [BCONPtr
] -> Assembler Word
246 lit l
= AllocLit l
return
248 label
:: Word16
-> Assembler
()
249 label w
= AllocLabel w
(return ())
251 emit
:: Word16
-> [Operand
] -> Assembler
()
252 emit w ops
= Emit w ops
(return ())
254 type LabelEnv
= Word16
-> Word
256 largeOp
:: Bool -> Operand
-> Bool
257 largeOp long_jumps op
= case op
of
260 LabelOp _
-> long_jumps
263 runAsm
:: DynFlags
-> Bool -> LabelEnv
-> Assembler a
-> StateT AsmState
IO a
264 runAsm dflags long_jumps e
= go
266 go
(NullAsm x
) = return x
267 go
(AllocPtr p_io k
) = do
269 w
<- state
$ \(st_i0
,st_l0
,st_p0
) ->
270 let st_p1
= addToSS st_p0 p
271 in (sizeSS st_p0
, (st_i0
,st_l0
,st_p1
))
273 go
(AllocLit lits k
) = do
274 w
<- state
$ \(st_i0
,st_l0
,st_p0
) ->
275 let st_l1
= addListToSS st_l0 lits
276 in (sizeSS st_l0
, (st_i0
,st_l1
,st_p0
))
278 go
(AllocLabel _ k
) = go k
279 go
(Emit w ops k
) = do
280 let largeOps
= any (largeOp long_jumps
) ops
282 | largeOps
= largeArgInstr w
284 words = concatMap expand ops
285 expand
(SmallOp w
) = [w
]
286 expand
(LabelOp w
) = expand
(Op
(e w
))
287 expand
(Op w
) = if largeOps
then largeArg dflags w
else [fromIntegral w
]
288 -- expand (LargeOp w) = largeArg dflags w
289 state
$ \(st_i0
,st_l0
,st_p0
) ->
290 let st_i1
= addListToSS st_i0
(opcode
: words)
291 in ((), (st_i1
,st_l0
,st_p0
))
294 type LabelEnvMap
= Map Word16 Word
296 data InspectState
= InspectState
297 { instrCount
:: !Word
300 , lblEnv
:: LabelEnvMap
303 inspectAsm
:: DynFlags
-> Bool -> Word
-> Assembler a
-> (Word
, LabelEnvMap
)
304 inspectAsm dflags long_jumps initial_offset
305 = go
(InspectState initial_offset
0 0 Map
.empty)
307 go s
(NullAsm _
) = (instrCount s
, lblEnv s
)
308 go s
(AllocPtr _ k
) = go
(s
{ ptrCount
= n
+ 1 }) (k n
)
310 go s
(AllocLit ls k
) = go
(s
{ litCount
= n
+ genericLength ls
}) (k n
)
312 go s
(AllocLabel lbl k
) = go s
' k
313 where s
' = s
{ lblEnv
= Map
.insert lbl
(instrCount s
) (lblEnv s
) }
314 go s
(Emit _ ops k
) = go s
' k
316 s
' = s
{ instrCount
= instrCount s
+ size
}
317 size
= sum (map count ops
) + 1
318 largeOps
= any (largeOp long_jumps
) ops
319 count
(SmallOp _
) = 1
320 count
(LabelOp _
) = count
(Op
0)
321 count
(Op _
) = if largeOps
then largeArg16s dflags
else 1
322 -- count (LargeOp _) = largeArg16s dflags
324 -- Bring in all the bci_ bytecode constants.
325 #include
"rts/Bytecodes.h"
327 largeArgInstr
:: Word16
-> Word16
328 largeArgInstr bci
= bci_FLAG_LARGE_ARGS
.|
. bci
330 largeArg
:: DynFlags
-> Word
-> [Word16
]
332 | wORD_SIZE_IN_BITS dflags
== 64
333 = [fromIntegral (w `shiftR`
48),
334 fromIntegral (w `shiftR`
32),
335 fromIntegral (w `shiftR`
16),
337 | wORD_SIZE_IN_BITS dflags
== 32
338 = [fromIntegral (w `shiftR`
16),
340 |
otherwise = error "wORD_SIZE_IN_BITS not 32 or 64?"
342 largeArg16s
:: DynFlags
-> Word
343 largeArg16s dflags | wORD_SIZE_IN_BITS dflags
== 64 = 4
346 assembleI
:: DynFlags
349 assembleI dflags i
= case i
of
350 STKCHECK n
-> emit bci_STKCHECK
[Op n
]
351 PUSH_L o1
-> emit bci_PUSH_L
[SmallOp o1
]
352 PUSH_LL o1 o2
-> emit bci_PUSH_LL
[SmallOp o1
, SmallOp o2
]
353 PUSH_LLL o1 o2 o3
-> emit bci_PUSH_LLL
[SmallOp o1
, SmallOp o2
, SmallOp o3
]
354 PUSH8 o1
-> emit bci_PUSH8
[SmallOp o1
]
355 PUSH16 o1
-> emit bci_PUSH16
[SmallOp o1
]
356 PUSH32 o1
-> emit bci_PUSH32
[SmallOp o1
]
357 PUSH8_W o1
-> emit bci_PUSH8_W
[SmallOp o1
]
358 PUSH16_W o1
-> emit bci_PUSH16_W
[SmallOp o1
]
359 PUSH32_W o1
-> emit bci_PUSH32_W
[SmallOp o1
]
360 PUSH_G nm
-> do p
<- ptr
(BCOPtrName nm
)
361 emit bci_PUSH_G
[Op p
]
362 PUSH_PRIMOP op
-> do p
<- ptr
(BCOPtrPrimOp op
)
363 emit bci_PUSH_G
[Op p
]
364 PUSH_BCO proto
-> do let ul_bco
= assembleBCO dflags proto
365 p
<- ioptr
(liftM BCOPtrBCO ul_bco
)
366 emit bci_PUSH_G
[Op p
]
367 PUSH_ALTS proto
-> do let ul_bco
= assembleBCO dflags proto
368 p
<- ioptr
(liftM BCOPtrBCO ul_bco
)
369 emit bci_PUSH_ALTS
[Op p
]
370 PUSH_ALTS_UNLIFTED proto pk
371 -> do let ul_bco
= assembleBCO dflags proto
372 p
<- ioptr
(liftM BCOPtrBCO ul_bco
)
373 emit
(push_alts pk
) [Op p
]
374 PUSH_PAD8
-> emit bci_PUSH_PAD8
[]
375 PUSH_PAD16
-> emit bci_PUSH_PAD16
[]
376 PUSH_PAD32
-> emit bci_PUSH_PAD32
[]
377 PUSH_UBX8 lit
-> do np
<- literal lit
378 emit bci_PUSH_UBX8
[Op np
]
379 PUSH_UBX16 lit
-> do np
<- literal lit
380 emit bci_PUSH_UBX16
[Op np
]
381 PUSH_UBX32 lit
-> do np
<- literal lit
382 emit bci_PUSH_UBX32
[Op np
]
383 PUSH_UBX lit nws
-> do np
<- literal lit
384 emit bci_PUSH_UBX
[Op np
, SmallOp nws
]
386 PUSH_APPLY_N
-> emit bci_PUSH_APPLY_N
[]
387 PUSH_APPLY_V
-> emit bci_PUSH_APPLY_V
[]
388 PUSH_APPLY_F
-> emit bci_PUSH_APPLY_F
[]
389 PUSH_APPLY_D
-> emit bci_PUSH_APPLY_D
[]
390 PUSH_APPLY_L
-> emit bci_PUSH_APPLY_L
[]
391 PUSH_APPLY_P
-> emit bci_PUSH_APPLY_P
[]
392 PUSH_APPLY_PP
-> emit bci_PUSH_APPLY_PP
[]
393 PUSH_APPLY_PPP
-> emit bci_PUSH_APPLY_PPP
[]
394 PUSH_APPLY_PPPP
-> emit bci_PUSH_APPLY_PPPP
[]
395 PUSH_APPLY_PPPPP
-> emit bci_PUSH_APPLY_PPPPP
[]
396 PUSH_APPLY_PPPPPP
-> emit bci_PUSH_APPLY_PPPPPP
[]
398 SLIDE n by
-> emit bci_SLIDE
[SmallOp n
, SmallOp by
]
399 ALLOC_AP n
-> emit bci_ALLOC_AP
[SmallOp n
]
400 ALLOC_AP_NOUPD n
-> emit bci_ALLOC_AP_NOUPD
[SmallOp n
]
401 ALLOC_PAP arity n
-> emit bci_ALLOC_PAP
[SmallOp arity
, SmallOp n
]
402 MKAP off sz
-> emit bci_MKAP
[SmallOp off
, SmallOp sz
]
403 MKPAP off sz
-> emit bci_MKPAP
[SmallOp off
, SmallOp sz
]
404 UNPACK n
-> emit bci_UNPACK
[SmallOp n
]
405 PACK dcon sz
-> do itbl_no
<- lit
[BCONPtrItbl
(getName dcon
)]
406 emit bci_PACK
[Op itbl_no
, SmallOp sz
]
407 LABEL lbl
-> label lbl
408 TESTLT_I i l
-> do np
<- int i
409 emit bci_TESTLT_I
[Op np
, LabelOp l
]
410 TESTEQ_I i l
-> do np
<- int i
411 emit bci_TESTEQ_I
[Op np
, LabelOp l
]
412 TESTLT_W w l
-> do np
<- word w
413 emit bci_TESTLT_W
[Op np
, LabelOp l
]
414 TESTEQ_W w l
-> do np
<- word w
415 emit bci_TESTEQ_W
[Op np
, LabelOp l
]
416 TESTLT_F f l
-> do np
<- float f
417 emit bci_TESTLT_F
[Op np
, LabelOp l
]
418 TESTEQ_F f l
-> do np
<- float f
419 emit bci_TESTEQ_F
[Op np
, LabelOp l
]
420 TESTLT_D d l
-> do np
<- double d
421 emit bci_TESTLT_D
[Op np
, LabelOp l
]
422 TESTEQ_D d l
-> do np
<- double d
423 emit bci_TESTEQ_D
[Op np
, LabelOp l
]
424 TESTLT_P i l
-> emit bci_TESTLT_P
[SmallOp i
, LabelOp l
]
425 TESTEQ_P i l
-> emit bci_TESTEQ_P
[SmallOp i
, LabelOp l
]
426 CASEFAIL
-> emit bci_CASEFAIL
[]
427 SWIZZLE stkoff n
-> emit bci_SWIZZLE
[SmallOp stkoff
, SmallOp n
]
428 JMP l
-> emit bci_JMP
[LabelOp l
]
429 ENTER
-> emit bci_ENTER
[]
430 RETURN
-> emit bci_RETURN
[]
431 RETURN_UBX rep
-> emit
(return_ubx rep
) []
432 CCALL off m_addr i
-> do np
<- addr m_addr
433 emit bci_CCALL
[SmallOp off
, Op np
, SmallOp i
]
434 BRK_FUN
index uniq cc
-> do p1
<- ptr BCOPtrBreakArray
435 q
<- int
(getKey uniq
)
437 emit bci_BRK_FUN
[Op p1
, SmallOp
index,
441 literal
(MachLabel fs
(Just sz
) _
)
442 | platformOS
(targetPlatform dflags
) == OSMinGW32
443 = litlabel
(appendFS fs
(mkFastString
('@':show sz
)))
444 -- On Windows, stdcall labels have a suffix indicating the no. of
445 -- arg words, e.g. foo@8. testcase: ffi012(ghci)
446 literal
(MachLabel fs _ _
) = litlabel fs
447 literal MachNullAddr
= int
0
448 literal
(MachFloat r
) = float
(fromRational r
)
449 literal
(MachDouble r
) = double
(fromRational r
)
450 literal
(MachChar c
) = int
(ord c
)
451 literal
(MachStr bs
) = lit
[BCONPtrStr bs
]
452 -- MachStr requires a zero-terminator when emitted
453 literal
(LitNumber nt i _
) = case nt
of
454 LitNumInt
-> int
(fromIntegral i
)
455 LitNumWord
-> int
(fromIntegral i
)
456 LitNumInt64
-> int64
(fromIntegral i
)
457 LitNumWord64
-> int64
(fromIntegral i
)
458 LitNumInteger
-> panic
"ByteCodeAsm.literal: LitNumInteger"
459 LitNumNatural
-> panic
"ByteCodeAsm.literal: LitNumNatural"
461 litlabel fs
= lit
[BCONPtrLbl fs
]
462 addr
(RemotePtr a
) = words [fromIntegral a
]
463 float
= words . mkLitF
464 double
= words . mkLitD dflags
466 int64
= words . mkLitI64 dflags
467 words ws
= lit
(map BCONPtrWord ws
)
470 isLarge
:: Word
-> Bool
471 isLarge n
= n
> 65535
473 push_alts
:: ArgRep
-> Word16
474 push_alts V
= bci_PUSH_ALTS_V
475 push_alts P
= bci_PUSH_ALTS_P
476 push_alts N
= bci_PUSH_ALTS_N
477 push_alts L
= bci_PUSH_ALTS_L
478 push_alts F
= bci_PUSH_ALTS_F
479 push_alts D
= bci_PUSH_ALTS_D
480 push_alts V16
= error "push_alts: vector"
481 push_alts V32
= error "push_alts: vector"
482 push_alts V64
= error "push_alts: vector"
484 return_ubx
:: ArgRep
-> Word16
485 return_ubx V
= bci_RETURN_V
486 return_ubx P
= bci_RETURN_P
487 return_ubx N
= bci_RETURN_N
488 return_ubx L
= bci_RETURN_L
489 return_ubx F
= bci_RETURN_F
490 return_ubx D
= bci_RETURN_D
491 return_ubx V16
= error "return_ubx: vector"
492 return_ubx V32
= error "return_ubx: vector"
493 return_ubx V64
= error "return_ubx: vector"
495 -- Make lists of host-sized words for literals, so that when the
496 -- words are placed in memory at increasing addresses, the
497 -- bit pattern is correct for the host's word size and endianness.
498 mkLitI
:: Int -> [Word
]
499 mkLitF
:: Float -> [Word
]
500 mkLitD
:: DynFlags
-> Double -> [Word
]
501 mkLitI64
:: DynFlags
-> Int64
-> [Word
]
505 arr
<- newArray_
((0::Int),0)
507 f_arr
<- castSTUArray arr
508 w0
<- readArray f_arr
0
513 | wORD_SIZE dflags
== 4
515 arr
<- newArray_
((0::Int),1)
517 d_arr
<- castSTUArray arr
518 w0
<- readArray d_arr
0
519 w1
<- readArray d_arr
1
520 return [w0
:: Word
, w1
]
522 | wORD_SIZE dflags
== 8
524 arr
<- newArray_
((0::Int),0)
526 d_arr
<- castSTUArray arr
527 w0
<- readArray d_arr
0
531 = panic
"mkLitD: Bad wORD_SIZE"
534 | wORD_SIZE dflags
== 4
536 arr
<- newArray_
((0::Int),1)
538 d_arr
<- castSTUArray arr
539 w0
<- readArray d_arr
0
540 w1
<- readArray d_arr
1
541 return [w0
:: Word
,w1
]
543 | wORD_SIZE dflags
== 8
545 arr
<- newArray_
((0::Int),0)
547 d_arr
<- castSTUArray arr
548 w0
<- readArray d_arr
0
552 = panic
"mkLitI64: Bad wORD_SIZE"
554 mkLitI i
= [fromIntegral i
:: Word
]
556 iNTERP_STACK_CHECK_THRESH
:: Int
557 iNTERP_STACK_CHECK_THRESH
= INTERP_STACK_CHECK_THRESH