root/compiler/prelude/ForeignCall.lhs

Revision ae04bd43a2640e17a9035f170d76dae356082f88, 11.1 KB (checked in by Ian Lynagh <igloo@…>, 3 months ago)

Implement "value" imports with the CAPI

This allows us to import values (i.e. non-functions) with the CAPI.
This means we can access values even if (on some or all platforms)
they are simple #defines.

  • Property mode set to 100644
Line 
1%
2% (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
3%
4\section[Foreign]{Foreign calls}
5
6\begin{code}
7{-# LANGUAGE DeriveDataTypeable #-}
8
9module ForeignCall (
10        ForeignCall(..), isSafeForeignCall,
11        Safety(..), playSafe, playInterruptible,
12
13        CExportSpec(..), CLabelString, isCLabelString, pprCLabelString,
14        CCallSpec(..),
15        CCallTarget(..), isDynamicTarget,
16        CCallConv(..), defaultCCallConv, ccallConvToInt, ccallConvAttribute,
17
18        Header(..), CType(..),
19    ) where
20
21import FastString
22import Binary
23import Outputable
24import Module
25
26import Data.Char
27import Data.Data
28\end{code}
29
30
31%************************************************************************
32%*                                                                      *
33\subsubsection{Data types}
34%*                                                                      *
35%************************************************************************
36
37\begin{code}
38newtype ForeignCall = CCall CCallSpec
39  deriving Eq
40  {-! derive: Binary !-}
41
42isSafeForeignCall :: ForeignCall -> Bool
43isSafeForeignCall (CCall (CCallSpec _ _ safe)) = playSafe safe
44
45-- We may need more clues to distinguish foreign calls
46-- but this simple printer will do for now
47instance Outputable ForeignCall where
48  ppr (CCall cc)  = ppr cc
49\end{code}
50
51
52\begin{code}
53data Safety
54  = PlaySafe            -- Might invoke Haskell GC, or do a call back, or
55                        -- switch threads, etc.  So make sure things are
56                        -- tidy before the call. Additionally, in the threaded
57                        -- RTS we arrange for the external call to be executed
58                        -- by a separate OS thread, i.e., _concurrently_ to the
59                        -- execution of other Haskell threads.
60
61  | PlayInterruptible   -- Like PlaySafe, but additionally
62                        -- the worker thread running this foreign call may
63                        -- be unceremoniously killed, so it must be scheduled
64                        -- on an unbound thread.
65
66  | PlayRisky           -- None of the above can happen; the call will return
67                        -- without interacting with the runtime system at all
68  deriving ( Eq, Show, Data, Typeable )
69        -- Show used just for Show Lex.Token, I think
70  {-! derive: Binary !-}
71
72instance Outputable Safety where
73  ppr PlaySafe = ptext (sLit "safe")
74  ppr PlayInterruptible = ptext (sLit "interruptible")
75  ppr PlayRisky = ptext (sLit "unsafe")
76
77playSafe :: Safety -> Bool
78playSafe PlaySafe = True
79playSafe PlayInterruptible = True
80playSafe PlayRisky = False
81
82playInterruptible :: Safety -> Bool
83playInterruptible PlayInterruptible = True
84playInterruptible _ = False
85\end{code}
86
87
88%************************************************************************
89%*                                                                      *
90\subsubsection{Calling C}
91%*                                                                      *
92%************************************************************************
93
94\begin{code}
95data CExportSpec
96  = CExportStatic               -- foreign export ccall foo :: ty
97        CLabelString            -- C Name of exported function
98        CCallConv
99  deriving (Data, Typeable)
100  {-! derive: Binary !-}
101
102data CCallSpec
103  =  CCallSpec  CCallTarget     -- What to call
104                CCallConv       -- Calling convention to use.
105                Safety
106  deriving( Eq )
107  {-! derive: Binary !-}
108\end{code}
109
110The call target:
111
112\begin{code}
113
114-- | How to call a particular function in C-land.
115data CCallTarget
116  -- An "unboxed" ccall# to named function in a particular package.
117  = StaticTarget
118        CLabelString                    -- C-land name of label.
119
120        (Maybe PackageId)               -- What package the function is in.
121                                        -- If Nothing, then it's taken to be in the current package.
122                                        -- Note: This information is only used for PrimCalls on Windows.
123                                        --       See CLabel.labelDynamic and CoreToStg.coreToStgApp
124                                        --       for the difference in representation between PrimCalls
125                                        --       and ForeignCalls. If the CCallTarget is representing
126                                        --       a regular ForeignCall then it's safe to set this to Nothing.
127
128  -- The first argument of the import is the name of a function pointer (an Addr#).
129  --    Used when importing a label as "foreign import ccall "dynamic" ..."
130        Bool                            -- True => really a function
131                                        -- False => a value; only
132                                        -- allowed in CAPI imports
133  | DynamicTarget
134
135  deriving( Eq, Data, Typeable )
136  {-! derive: Binary !-}
137
138isDynamicTarget :: CCallTarget -> Bool
139isDynamicTarget DynamicTarget = True
140isDynamicTarget _             = False
141\end{code}
142
143
144Stuff to do with calling convention:
145
146ccall:          Caller allocates parameters, *and* deallocates them.
147
148stdcall:        Caller allocates parameters, callee deallocates.
149                Function name has @N after it, where N is number of arg bytes
150                e.g.  _Foo@8
151
152ToDo: The stdcall calling convention is x86 (win32) specific,
153so perhaps we should emit a warning if it's being used on other
154platforms.
155
156See: http://www.programmersheaven.com/2/Calling-conventions
157
158\begin{code}
159data CCallConv = CCallConv | CApiConv | StdCallConv
160               | CmmCallConv | PrimCallConv
161  deriving (Eq, Data, Typeable)
162  {-! derive: Binary !-}
163
164instance Outputable CCallConv where
165  ppr StdCallConv = ptext (sLit "stdcall")
166  ppr CCallConv   = ptext (sLit "ccall")
167  ppr CApiConv    = ptext (sLit "capi")
168  ppr CmmCallConv = ptext (sLit "C--")
169  ppr PrimCallConv = ptext (sLit "prim")
170
171defaultCCallConv :: CCallConv
172defaultCCallConv = CCallConv
173
174ccallConvToInt :: CCallConv -> Int
175ccallConvToInt StdCallConv = 0
176ccallConvToInt CCallConv   = 1
177ccallConvToInt CApiConv    = panic "ccallConvToInt CApiConv"
178ccallConvToInt (CmmCallConv {})  = panic "ccallConvToInt CmmCallConv"
179ccallConvToInt (PrimCallConv {}) = panic "ccallConvToInt PrimCallConv"
180\end{code}
181
182Generate the gcc attribute corresponding to the given
183calling convention (used by PprAbsC):
184
185\begin{code}
186ccallConvAttribute :: CCallConv -> SDoc
187ccallConvAttribute StdCallConv       = text "__attribute__((__stdcall__))"
188ccallConvAttribute CCallConv         = empty
189ccallConvAttribute CApiConv          = empty
190ccallConvAttribute (CmmCallConv {})  = panic "ccallConvAttribute CmmCallConv"
191ccallConvAttribute (PrimCallConv {}) = panic "ccallConvAttribute PrimCallConv"
192\end{code}
193
194\begin{code}
195type CLabelString = FastString          -- A C label, completely unencoded
196
197pprCLabelString :: CLabelString -> SDoc
198pprCLabelString lbl = ftext lbl
199
200isCLabelString :: CLabelString -> Bool  -- Checks to see if this is a valid C label
201isCLabelString lbl
202  = all ok (unpackFS lbl)
203  where
204    ok c = isAlphaNum c || c == '_' || c == '.'
205        -- The '.' appears in e.g. "foo.so" in the
206        -- module part of a ExtName.  Maybe it should be separate
207\end{code}
208
209
210Printing into C files:
211
212\begin{code}
213instance Outputable CExportSpec where
214  ppr (CExportStatic str _) = pprCLabelString str
215
216instance Outputable CCallSpec where
217  ppr (CCallSpec fun cconv safety)
218    = hcat [ ifPprDebug callconv, ppr_fun fun ]
219    where
220      callconv = text "{-" <> ppr cconv <> text "-}"
221
222      gc_suf | playSafe safety = text "_GC"
223             | otherwise       = empty
224
225      ppr_fun (StaticTarget fn mPkgId isFun)
226        = text (if isFun then "__pkg_ccall"
227                         else "__pkg_ccall_value")
228       <> gc_suf
229       <+> (case mPkgId of
230            Nothing -> empty
231            Just pkgId -> ppr pkgId)
232       <+> pprCLabelString fn
233
234      ppr_fun DynamicTarget
235        = text "__dyn_ccall" <> gc_suf <+> text "\"\""
236\end{code}
237
238\begin{code}
239-- The filename for a C header file
240newtype Header = Header FastString
241    deriving (Eq, Data, Typeable)
242
243instance Outputable Header where
244    ppr (Header h) = quotes $ ppr h
245
246-- | A C type, used in CAPI FFI calls
247data CType = CType (Maybe Header) -- header to include for this type
248                   FastString     -- the type itself
249    deriving (Data, Typeable)
250
251instance Outputable CType where
252    ppr (CType mh ct) = hDoc <+> ftext ct
253        where hDoc = case mh of
254                     Nothing -> empty
255                     Just h -> ppr h
256\end{code}
257
258
259%************************************************************************
260%*                                                                      *
261\subsubsection{Misc}
262%*                                                                      *
263%************************************************************************
264
265\begin{code}
266{-* Generated by DrIFT-v1.0 : Look, but Don't Touch. *-}
267instance Binary ForeignCall where
268    put_ bh (CCall aa) = put_ bh aa
269    get bh = do aa <- get bh; return (CCall aa)
270
271instance Binary Safety where
272    put_ bh PlaySafe = do
273            putByte bh 0
274    put_ bh PlayInterruptible = do
275            putByte bh 1
276    put_ bh PlayRisky = do
277            putByte bh 2
278    get bh = do
279            h <- getByte bh
280            case h of
281              0 -> do return PlaySafe
282              1 -> do return PlayInterruptible
283              _ -> do return PlayRisky
284
285instance Binary CExportSpec where
286    put_ bh (CExportStatic aa ab) = do
287            put_ bh aa
288            put_ bh ab
289    get bh = do
290          aa <- get bh
291          ab <- get bh
292          return (CExportStatic aa ab)
293
294instance Binary CCallSpec where
295    put_ bh (CCallSpec aa ab ac) = do
296            put_ bh aa
297            put_ bh ab
298            put_ bh ac
299    get bh = do
300          aa <- get bh
301          ab <- get bh
302          ac <- get bh
303          return (CCallSpec aa ab ac)
304
305instance Binary CCallTarget where
306    put_ bh (StaticTarget aa ab ac) = do
307            putByte bh 0
308            put_ bh aa
309            put_ bh ab
310            put_ bh ac
311    put_ bh DynamicTarget = do
312            putByte bh 1
313    get bh = do
314            h <- getByte bh
315            case h of
316              0 -> do aa <- get bh
317                      ab <- get bh
318                      ac <- get bh
319                      return (StaticTarget aa ab ac)
320              _ -> do return DynamicTarget
321
322instance Binary CCallConv where
323    put_ bh CCallConv = do
324            putByte bh 0
325    put_ bh StdCallConv = do
326            putByte bh 1
327    put_ bh PrimCallConv = do
328            putByte bh 2
329    put_ bh CmmCallConv = do
330            putByte bh 3
331    put_ bh CApiConv = do
332            putByte bh 4
333    get bh = do
334            h <- getByte bh
335            case h of
336              0 -> do return CCallConv
337              1 -> do return StdCallConv
338              2 -> do return PrimCallConv
339              3 -> do return CmmCallConv
340              _ -> do return CApiConv
341
342instance Binary CType where
343    put_ bh (CType mh fs) = do put_ bh mh
344                               put_ bh fs
345    get bh = do mh <- get bh
346                fs <- get bh
347                return (CType mh fs)
348
349instance Binary Header where
350    put_ bh (Header h) = put_ bh h
351    get bh = do h <- get bh
352                return (Header h)
353\end{code}
Note: See TracBrowser for help on using the browser.