import CoreSyn
-import DsCCall ( dsCCall, mkCCall, boxResult, unboxArg, resultWrapper )
+import DsCCall ( dsCCall, mkFCall, boxResult, unboxArg, resultWrapper )
import DsMonad
import HsSyn ( ExtName(..), ForeignDecl(..), isDynamicExtName, ForKind(..) )
import HsDecls ( extNameStatic )
-import CallConv
import TcHsSyn ( TypecheckedForeignDecl )
import CoreUtils ( exprType, mkInlineMe )
import Id ( Id, idType, idName, mkVanillaGlobal, mkSysLocal,
Type, mkFunTys, mkForAllTys, mkTyConApp,
mkFunTy, splitAppTy, applyTy, funResultTy
)
-import PrimOp ( CCall(..), CCallTarget(..), dynamicTarget )
+import ForeignCall ( ForeignCall(..), CCallSpec(..),
+ Safety(..), playSafe,
+ CCallTarget(..), dynamicTarget,
+ CCallConv(..), ccallConvToInt
+ )
import TysWiredIn ( unitTy, addrTy, stablePtrTyCon )
import TysPrim ( addrPrimTy )
import PrelNames ( hasKey, ioTyConKey, deRefStablePtrName, newStablePtrName,
FoLabel -> True
_ -> False
- (FoImport uns) = imp_exp
-
+ FoImport uns = imp_exp
\end{code}
Desugaring foreign imports is just the matter of creating a binding
\begin{code}
dsFImport :: Id
-> Type -- Type of foreign import.
- -> Bool -- True <=> cannot re-enter the Haskell RTS
+ -> Safety -- Whether can re-enter the Haskell RTS, do GC etc
-> ExtName
- -> CallConv
+ -> CCallConv
-> DsM [Binding]
-dsFImport fn_id ty unsafe ext_name cconv
+dsFImport fn_id ty safety ext_name cconv
= let
(tvs, fun_ty) = splitForAllTys ty
(arg_tys, io_res_ty) = splitFunTys fun_ty
let
work_arg_ids = [v | Var v <- val_args] -- All guaranteed to be vars
- -- these are the ids we pass to boxResult, which are used to decide
+ -- These are the ids we pass to boxResult, which are used to decide
-- whether to touch# an argument after the call (used to keep
-- ForeignObj#s live across a 'safe' foreign import).
- maybe_arg_ids | unsafe = []
- | otherwise = work_arg_ids
+ maybe_arg_ids | playSafe safety = work_arg_ids
+ | otherwise = []
in
boxResult maybe_arg_ids io_res_ty `thenDs` \ (ccall_result_ty, res_wrapper) ->
-- Build the worker
worker_ty = mkForAllTys tvs (mkFunTys (map idType work_arg_ids) ccall_result_ty)
- the_ccall = CCall lbl False (not unsafe) cconv
- the_ccall_app = mkCCall ccall_uniq the_ccall val_args ccall_result_ty
+ the_ccall = CCall (CCallSpec lbl cconv safety False)
+ the_ccall_app = mkFCall ccall_uniq the_ccall val_args ccall_result_ty
work_rhs = mkLams tvs (mkLams work_arg_ids the_ccall_app)
work_id = mkSysLocal SLIT("$wccall") work_uniq worker_ty
-> Type -- Type of foreign export.
-> Module
-> ExtName
- -> CallConv
+ -> CCallConv
-> Bool -- True => invoke IO action that's hanging off
-- the first argument's stable pointer
-> DsM ( Id -- The foreign-exported Id
-> Type -- Type of foreign export.
-> Module
-> ExtName
- -> CallConv
+ -> CCallConv
-> DsM (Id, [Binding], SDoc, SDoc)
dsFExportDynamic i ty mod_name ext_name cconv =
newSysLocalDs ty `thenDs` \ fe_id ->
to be entered using an external calling convention
(stdcall, ccall).
-}
- adj_args = [ mkIntLitInt (callConvToInt cconv)
+ adj_args = [ mkIntLitInt (ccallConvToInt cconv)
, Var stbl_value
, mkLit (MachLabel (_PK_ fe_nm))
]
-- (probably in the RTS.)
adjustor = SLIT("createAdjustor")
in
- dsCCall adjustor adj_args False False io_res_ty `thenDs` \ ccall_adj ->
+ dsCCall adjustor adj_args PlayRisky False io_res_ty `thenDs` \ ccall_adj ->
+ -- PlayRisky: the adjustor doesn't allocate in the Haskell heap or do a callback
let ccall_adj_ty = exprType ccall_adj
ccall_io_adj = mkLams [stbl_value] $
Note (Coerce io_res_ty ccall_adj_ty)
ccall_adj
- in
- let io_app = mkLams tvs $
+ io_app = mkLams tvs $
mkLams [cback] $
stbl_app ccall_io_adj res_ty
fed = (i `setInlinePragma` neverInlinePrag, io_app)
where
(tvs,sans_foralls) = splitForAllTys ty
([arg_ty], io_res_ty) = splitFunTys sans_foralls
-
Just (ioTyCon, [res_ty]) = splitTyConApp_maybe io_res_ty
-
export_ty = mkFunTy (mkTyConApp stablePtrTyCon [arg_ty]) arg_ty
- ioAddrTy :: Type -- IO Addr
- ioAddrTy = mkTyConApp ioTyCon [addrTy]
-
toCName :: Id -> String
toCName i = showSDoc (pprCode CStyle (ppr (idName i)))
\end{code}
-> Id
-> [Type]
-> Type
- -> CallConv
+ -> CCallConv
-> Bool
-> (SDoc, SDoc)
fexportEntry mod_nm c_nm helper args res_ty cc isDyn = (header_bits, c_bits)
cResType | res_ty_is_unit = text "void"
| otherwise = showStgType res_ty
- pprCconv
- | cc == cCallConv = empty
- | otherwise = pprCallConv cc
+ pprCconv = case cc of
+ CCallConv -> empty
+ StdCallConv -> ppr cc
declareResult = text "HaskellObj ret;"
needed by the Adjustor.c code to get the stack cleanup right.
-}
(proto_args, real_args)
- | cc == cCallConv && isDyn = ( text "a0" : text "a_" : mkCArgNames 1 (tail args)
- , head args : addrTy : tail args)
- | otherwise = (mkCArgNames 0 args, args)
+ = case cc of
+ CCallConv | isDyn -> ( text "a0" : text "a_" : mkCArgNames 1 (tail args)
+ , head args : addrTy : tail args)
+ other -> (mkCArgNames 0 args, args)
mkCArgNames :: Int -> [a] -> [SDoc]
mkCArgNames n as = zipWith (\ _ n -> text ('a':show n)) as [n..]