Desugaring foreign declarations (see also DsCCall).
\begin{code}
-{-# 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
-
module DsForeign ( dsForeigns ) where
#include "HsVersions.h"
import Module
import Name
import Type
+import TyCon
import Coercion
import TcType
+import Var
import HscTypes
import ForeignCall
do_decl (ForeignExport (L _ id) _ (CExport (CExportStatic ext_nm cconv))) = do
(h, c, _, _) <- dsFExport id (idType id) ext_nm cconv False
return (h, c, [id], [])
+
+ do_decl d = pprPanic "dsForeigns/do_decl" (ppr d)
\end{code}
dsFImport :: Id
-> ForeignImport
-> DsM ([Binding], SDoc, SDoc)
-dsFImport id (CImport cconv safety header lib spec) = do
+dsFImport id (CImport cconv safety _ _ spec) = do
(ids, h, c) <- dsCImport id spec cconv safety
return (ids, h, c)
-> CCallConv
-> Safety
-> DsM ([Binding], SDoc, SDoc)
-dsCImport id (CLabel cid) _ _ = do
- (resTy, foRhs) <- resultWrapper (idType id)
+dsCImport id (CLabel cid) cconv _ = do
+ let ty = idType id
+ (resTy, foRhs) <- resultWrapper ty
ASSERT(fromJust resTy `coreEqType` addrPrimTy) -- typechecker ensures this
- let rhs = foRhs (mkLit (MachLabel cid Nothing)) in
+ let
+ rhs = foRhs (Lit (MachLabel cid stdcall_info))
+ stdcall_info = fun_type_arg_stdcall_info cconv ty
+ in
return ([(id, rhs)], empty, empty)
+
dsCImport id (CFunction target) cconv safety
= dsFCall id (CCall (CCallSpec target cconv safety))
dsCImport id CWrapper cconv _
= dsFExportDynamic id cconv
+
+-- For stdcall labels, if the type was a FunPtr or newtype thereof,
+-- then we need to calculate the size of the arguments in order to add
+-- the @n suffix to the label.
+fun_type_arg_stdcall_info :: CCallConv -> Type -> Maybe Int
+fun_type_arg_stdcall_info StdCallConv ty
+ | Just (tc,[arg_ty]) <- splitTyConApp_maybe (repType ty),
+ tyConUnique tc == funPtrTyConKey
+ = let
+ (_tvs,sans_foralls) = tcSplitForAllTys arg_ty
+ (fe_arg_tys, _orig_res_ty) = tcSplitFunTys sans_foralls
+ in
+ Just $ sum (map (machRepByteWidth . typeMachRep . getPrimTyOf) fe_arg_tys)
+fun_type_arg_stdcall_info _other_conv _
+ = Nothing
\end{code}
%************************************************************************
\begin{code}
+dsFCall :: Id -> ForeignCall -> DsM ([(Id, Expr TyVar)], SDoc, SDoc)
dsFCall fn_id fcall = do
let
ty = idType fn_id
augmentResultDs
| forDotnet = do
- err_res <- newSysLocalDs addrPrimTy
return (\ (mb_res_ty, resWrap) ->
case mb_res_ty of
Nothing -> (Just (mkTyConApp (tupleTyCon Unboxed 1)
For each `@foreign export foo@' in a module M we generate:
\begin{itemize}
\item a C function `@foo@', which calls
-\item a Haskell stub `@M.$ffoo@', which calls
+\item a Haskell stub `@M.\$ffoo@', which calls
\end{itemize}
the user-written Haskell function `@M.foo@'.
(res_ty, -- t
is_IO_res_ty) <- -- Bool
case tcSplitIOType_maybe orig_res_ty of
- Just (ioTyCon, res_ty, co) -> return (res_ty, True)
+ Just (_ioTyCon, res_ty, _co) -> return (res_ty, True)
-- The function already returns IO t
-- ToDo: what about the coercion?
Nothing -> return (orig_res_ty, False)
-}
adj_args = [ mkIntLitInt (ccallConvToInt cconv)
, Var stbl_value
- , mkLit (MachLabel fe_nm mb_sz_args)
- , mkLit (mkStringLit typestring)
+ , Lit (MachLabel fe_nm mb_sz_args)
+ , Lit (mkMachString typestring)
]
-- name of external entry point providing these services.
-- (probably in the RTS.)
pprCconv = case cc of
CCallConv -> empty
StdCallConv -> text (ccallConvAttribute cc)
+ CmmCallConv -> panic "mkFExportCBits/pprCconv CmmCallConv"
header_bits = ptext (sLit "extern") <+> fun_proto <> semi
-- this information to hand, but we know what GHC's conventions
-- are for passing around the primitive Haskell types, so we
-- use that instead. I hope the two coincide --SDM
+typeMachRep :: Type -> MachRep
typeMachRep ty = argMachRep (typeCgRep ty)
mkHObj :: Type -> SDoc
Just (tc,_) -> tc
Nothing -> pprPanic "showFFIType" (ppr t)
+insertRetAddr :: CCallConv -> [(SDoc, SDoc, Type, MachRep)]
+ -> [(SDoc, SDoc, Type, MachRep)]
#if !defined(x86_64_TARGET_ARCH)
insertRetAddr CCallConv args = ret_addr_arg : args
insertRetAddr _ args = args
-- need to flush a register argument to the stack (See rts/Adjustor.c for
-- details).
insertRetAddr CCallConv args = go 0 args
- where go 6 args = ret_addr_arg : args
+ where go :: Int -> [(SDoc, SDoc, Type, MachRep)]
+ -> [(SDoc, SDoc, Type, MachRep)]
+ go 6 args = ret_addr_arg : args
go n (arg@(_,_,_,rep):args)
| I64 <- rep = arg : go (n+1) args
| otherwise = arg : go n args
- go n [] = []
+ go _ [] = []
insertRetAddr _ args = args
#endif
+ret_addr_arg :: (SDoc, SDoc, Type, MachRep)
ret_addr_arg = (text "original_return_addr", text "void*", undefined,
typeMachRep addrPrimTy)