%
% (c) The GRASP/AQUA Project, Glasgow University, 19921998
%
\section[Foreign]{Foreign calls}
\begin{code}
module ForeignCall (
ForeignCall(..),
Safety(..), playSafe,
CExportSpec(..), CLabelString, isCLabelString, pprCLabelString,
CCallSpec(..),
CCallTarget(..), isDynamicTarget,
CCallConv(..), defaultCCallConv, ccallConvToInt, ccallConvAttribute,
) where
import FastString
import Binary
import Outputable
import Module
import Data.Char
import Data.Data
\end{code}
%************************************************************************
%* *
\subsubsection{Data types}
%* *
%************************************************************************
\begin{code}
newtype ForeignCall = CCall CCallSpec
deriving Eq
instance Outputable ForeignCall where
ppr (CCall cc) = ppr cc
\end{code}
\begin{code}
data Safety
= PlaySafe
Bool
| PlayRisky
deriving ( Eq, Show, Data, Typeable )
instance Outputable Safety where
ppr (PlaySafe False) = ptext (sLit "safe")
ppr (PlaySafe True) = ptext (sLit "threadsafe")
ppr PlayRisky = ptext (sLit "unsafe")
playSafe :: Safety -> Bool
playSafe PlaySafe{} = True
playSafe PlayRisky = False
\end{code}
%************************************************************************
%* *
\subsubsection{Calling C}
%* *
%************************************************************************
\begin{code}
data CExportSpec
= CExportStatic
CLabelString
CCallConv
deriving (Data, Typeable)
data CCallSpec
= CCallSpec CCallTarget
CCallConv
Safety
deriving( Eq )
\end{code}
The call target:
\begin{code}
data CCallTarget
= StaticTarget
CLabelString
(Maybe PackageId)
| DynamicTarget
deriving( Eq, Data, Typeable )
isDynamicTarget :: CCallTarget -> Bool
isDynamicTarget DynamicTarget = True
isDynamicTarget _ = False
\end{code}
Stuff to do with calling convention:
ccall: Caller allocates parameters, *and* deallocates them.
stdcall: Caller allocates parameters, callee deallocates.
Function name has @N after it, where N is number of arg bytes
e.g. _Foo@8
ToDo: The stdcall calling convention is x86 (win32) specific,
so perhaps we should emit a warning if it's being used on other
platforms.
See: http://www.programmersheaven.com/2/Callingconventions
\begin{code}
data CCallConv = CCallConv | StdCallConv | CmmCallConv | PrimCallConv
deriving (Eq, Data, Typeable)
instance Outputable CCallConv where
ppr StdCallConv = ptext (sLit "stdcall")
ppr CCallConv = ptext (sLit "ccall")
ppr CmmCallConv = ptext (sLit "C--")
ppr PrimCallConv = ptext (sLit "prim")
defaultCCallConv :: CCallConv
defaultCCallConv = CCallConv
ccallConvToInt :: CCallConv -> Int
ccallConvToInt StdCallConv = 0
ccallConvToInt CCallConv = 1
\end{code}
Generate the gcc attribute corresponding to the given
calling convention (used by PprAbsC):
\begin{code}
ccallConvAttribute :: CCallConv -> String
ccallConvAttribute StdCallConv = "__attribute__((__stdcall__))"
ccallConvAttribute CCallConv = ""
\end{code}
\begin{code}
type CLabelString = FastString
pprCLabelString :: CLabelString -> SDoc
pprCLabelString lbl = ftext lbl
isCLabelString :: CLabelString -> Bool
isCLabelString lbl
= all ok (unpackFS lbl)
where
ok c = isAlphaNum c || c == '_' || c == '.'
\end{code}
Printing into C files:
\begin{code}
instance Outputable CExportSpec where
ppr (CExportStatic str _) = pprCLabelString str
instance Outputable CCallSpec where
ppr (CCallSpec fun cconv safety)
= hcat [ ifPprDebug callconv, ppr_fun fun ]
where
callconv = text "{-" <> ppr cconv <> text "-}"
gc_suf | playSafe safety = text "_GC"
| otherwise = empty
ppr_fun (StaticTarget fn Nothing)
= text "__pkg_ccall" <> gc_suf <+> pprCLabelString fn
ppr_fun (StaticTarget fn (Just pkgId))
= text "__pkg_ccall" <> gc_suf <+> ppr pkgId <+> pprCLabelString fn
ppr_fun DynamicTarget
= text "__dyn_ccall" <> gc_suf <+> text "\"\""
\end{code}
%************************************************************************
%* *
\subsubsection{Misc}
%* *
%************************************************************************
\begin{code}
instance Binary ForeignCall where
put_ bh (CCall aa) = put_ bh aa
get bh = do aa <- get bh; return (CCall aa)
instance Binary Safety where
put_ bh (PlaySafe aa) = do
putByte bh 0
put_ bh aa
put_ bh PlayRisky = do
putByte bh 1
get bh = do
h <- getByte bh
case h of
0 -> do aa <- get bh
return (PlaySafe aa)
_ -> do return PlayRisky
instance Binary CExportSpec where
put_ bh (CExportStatic aa ab) = do
put_ bh aa
put_ bh ab
get bh = do
aa <- get bh
ab <- get bh
return (CExportStatic aa ab)
instance Binary CCallSpec where
put_ bh (CCallSpec aa ab ac) = do
put_ bh aa
put_ bh ab
put_ bh ac
get bh = do
aa <- get bh
ab <- get bh
ac <- get bh
return (CCallSpec aa ab ac)
instance Binary CCallTarget where
put_ bh (StaticTarget aa ab) = do
putByte bh 0
put_ bh aa
put_ bh ab
put_ bh DynamicTarget = do
putByte bh 1
get bh = do
h <- getByte bh
case h of
0 -> do aa <- get bh
ab <- get bh
return (StaticTarget aa ab)
_ -> do return DynamicTarget
instance Binary CCallConv where
put_ bh CCallConv = do
putByte bh 0
put_ bh StdCallConv = do
putByte bh 1
put_ bh PrimCallConv = do
putByte bh 2
get bh = do
h <- getByte bh
case h of
0 -> do return CCallConv
1 -> do return StdCallConv
_ -> do return PrimCallConv
\end{code}