-{-# OPTIONS -w #-}
--- The above warning supression flag is a temporary kludge.
--- While working on this module you are encouraged to remove it and fix
--- any warnings in the module. See
--- http://hackage.haskell.org/trac/ghc/wiki/Commentary/CodingStyle#Warnings
--- for details
-
-----------------------------------------------------------------------------
--
-- Code generation for foreign calls.
import Constants
import StaticFlags
import Outputable
+import Module
import FastString
+import BasicTypes
import Control.Monad
where
(call_args, cmm_target)
= case target of
- StaticTarget lbl -> (args, CmmLit (CmmLabel
- (mkForeignLabel lbl call_size False)))
- DynamicTarget -> case args of (CmmHinted fn _):rest -> (rest, fn)
+ -- If the packageId is Nothing then the label is taken to be in the
+ -- package currently being compiled.
+ StaticTarget lbl mPkgId
+ -> let labelSource
+ = case mPkgId of
+ Nothing -> ForeignLabelInThisPackage
+ Just pkgId -> ForeignLabelInPackage pkgId
+ in ( args
+ , CmmLit (CmmLabel
+ (mkForeignLabel lbl call_size labelSource IsFunction)))
+
+ -- A label imported with "foreign import ccall "dynamic" ..."
+ -- Note: "dynamic" here doesn't mean "dynamic library".
+ -- Read the FFI spec for details.
+ DynamicTarget -> case args of
+ (CmmHinted fn _):rest -> (rest, fn)
+ [] -> panic "emitForeignCall: DynamicTarget []"
-- in the stdcall calling convention, the symbol needs @size appended
-- to it, where size is the total number of bytes of arguments. We
-- ToDo: this might not be correct for 64-bit API
arg_size rep = max (widthInBytes (typeWidth rep)) wORD_SIZE
-emitForeignCall _ (DNCall _) _ _
- = panic "emitForeignCall: DNCall"
-
-- alternative entry point, used by CmmParse
emitForeignCall'
-> C_SRT -- the SRT of the calls continuation
-> CmmReturnInfo
-> Code
-emitForeignCall' safety results target args vols srt ret
+emitForeignCall' safety results target args vols _srt ret
| not (playSafe safety) = do
temp_args <- load_args_into_temps args
let (caller_save, caller_load) = callerSaveVolatileRegs vols
stmtsC caller_load
emitLoadThreadState
-suspendThread = CmmLit (CmmLabel (mkRtsCodeLabel (sLit "suspendThread")))
-resumeThread = CmmLit (CmmLabel (mkRtsCodeLabel (sLit "resumeThread")))
+suspendThread, resumeThread :: CmmExpr
+suspendThread = CmmLit (CmmLabel (mkCmmCodeLabel rtsPackageId (fsLit "suspendThread")))
+resumeThread = CmmLit (CmmLabel (mkCmmCodeLabel rtsPackageId (fsLit "resumeThread")))
-- we might need to load arguments into temporaries before
--
-- This is a HACK; really it should be done in the back end, but
-- it's easier to generate the temporaries here.
+load_args_into_temps :: [CmmHinted CmmExpr] -> FCode [CmmHinted CmmExpr]
load_args_into_temps = mapM arg_assign_temp
where arg_assign_temp (CmmHinted e hint) = do
tmp <- maybe_assign_temp e
return (CmmHinted tmp hint)
+load_target_into_temp :: CmmCallTarget -> FCode CmmCallTarget
load_target_into_temp (CmmCallee expr conv) = do
tmp <- maybe_assign_temp expr
return (CmmCallee tmp conv)
load_target_into_temp other_target =
return other_target
+maybe_assign_temp :: CmmExpr -> FCode CmmExpr
maybe_assign_temp e
| hasNoGlobalRegs e = return e
| otherwise = do
-- This stuff can't be done in suspendThread/resumeThread, because it
-- refers to global registers which aren't available in the C world.
+emitSaveThreadState :: Code
emitSaveThreadState = do
-- CurrentTSO->sp = Sp;
stmtC $ CmmStore (cmmOffset stgCurrentTSO tso_SP) stgSp
stmtC (CmmStore (cmmOffset stgCurrentTSO tso_CCCS) curCCS)
-- CurrentNursery->free = Hp+1;
+emitCloseNursery :: Code
emitCloseNursery = stmtC $ CmmStore nursery_bdescr_free (cmmOffsetW stgHp 1)
+emitLoadThreadState :: Code
emitLoadThreadState = do
tso <- newTemp bWord -- TODO FIXME NOW
stmtsC [
bWord),
-- SpLim = tso->stack + RESERVED_STACK_WORDS;
CmmAssign spLim (cmmOffsetW (cmmOffset (CmmReg (CmmLocal tso)) tso_STACK)
- rESERVED_STACK_WORDS)
+ rESERVED_STACK_WORDS),
+ -- HpAlloc = 0;
+ -- HpAlloc is assumed to be set to non-zero only by a failed
+ -- a heap check, see HeapStackCheck.cmm:GC_GENERIC
+ CmmAssign hpAlloc (CmmLit zeroCLit)
]
emitOpenNursery
-- and load the current cost centre stack from the TSO when profiling:
stmtC (CmmStore curCCSAddr
(CmmLoad (cmmOffset (CmmReg (CmmLocal tso)) tso_CCCS) bWord))
+emitOpenNursery :: Code
emitOpenNursery = stmtsC [
-- Hp = CurrentNursery->free - 1;
CmmAssign hp (cmmOffsetW (CmmLoad nursery_bdescr_free gcWord) (-1)),
)
]
-
+nursery_bdescr_free, nursery_bdescr_start, nursery_bdescr_blocks :: CmmExpr
nursery_bdescr_free = cmmOffset stgCurrentNursery oFFSET_bdescr_free
nursery_bdescr_start = cmmOffset stgCurrentNursery oFFSET_bdescr_start
nursery_bdescr_blocks = cmmOffset stgCurrentNursery oFFSET_bdescr_blocks
+tso_SP, tso_STACK, tso_CCCS :: ByteOff
tso_SP = tsoFieldB oFFSET_StgTSO_sp
tso_STACK = tsoFieldB oFFSET_StgTSO_stack
tso_CCCS = tsoProfFieldB oFFSET_StgTSO_CCCS
tsoProfFieldB :: ByteOff -> ByteOff
tsoProfFieldB off = off + fixedHdrSize * wORD_SIZE
+stgSp, stgHp, stgCurrentTSO, stgCurrentNursery :: CmmExpr
stgSp = CmmReg sp
stgHp = CmmReg hp
stgCurrentTSO = CmmReg currentTSO
stgCurrentNursery = CmmReg currentNursery
+sp, spLim, hp, hpLim, currentTSO, currentNursery, hpAlloc :: CmmReg
sp = CmmGlobal Sp
spLim = CmmGlobal SpLim
hp = CmmGlobal Hp
hpLim = CmmGlobal HpLim
currentTSO = CmmGlobal CurrentTSO
currentNursery = CmmGlobal CurrentNursery
+hpAlloc = CmmGlobal HpAlloc
-- -----------------------------------------------------------------------------
-- For certain types passed to foreign calls, we adjust the actual