diff options
Diffstat (limited to 'ghc/compiler/codeGen')
-rw-r--r-- | ghc/compiler/codeGen/CgBindery.lhs | 58 | ||||
-rw-r--r-- | ghc/compiler/codeGen/CgCase.lhs | 13 | ||||
-rw-r--r-- | ghc/compiler/codeGen/CgCon.lhs | 77 | ||||
-rw-r--r-- | ghc/compiler/codeGen/CgConTbls.lhs | 38 | ||||
-rw-r--r-- | ghc/compiler/codeGen/CgExpr.lhs | 42 | ||||
-rw-r--r-- | ghc/compiler/codeGen/CgRetConv.lhs | 4 | ||||
-rw-r--r-- | ghc/compiler/codeGen/CgTailCall.lhs | 4 | ||||
-rw-r--r-- | ghc/compiler/codeGen/ClosureInfo.lhs | 130 | ||||
-rw-r--r-- | ghc/compiler/codeGen/CodeGen.lhs | 11 | ||||
-rw-r--r-- | ghc/compiler/codeGen/SMRep.lhs | 127 |
10 files changed, 201 insertions, 303 deletions
diff --git a/ghc/compiler/codeGen/CgBindery.lhs b/ghc/compiler/codeGen/CgBindery.lhs index 8cda07b537..92acdfbdd8 100644 --- a/ghc/compiler/codeGen/CgBindery.lhs +++ b/ghc/compiler/codeGen/CgBindery.lhs @@ -33,24 +33,24 @@ import CgMonad import CgUsages ( getHpRelOffset, getSpRelOffset, getRealSp ) import CgStackery ( freeStackSlots, addFreeSlots ) -import CLabel ( mkStaticClosureLabel, mkClosureLabel, +import CLabel ( mkClosureLabel, mkBitmapLabel, pprCLabel ) import ClosureInfo ( mkLFImported, mkLFArgument, LambdaFormInfo ) import BitSet ( mkBS, emptyBS ) import PrimRep ( isFollowableRep, getPrimRepSize ) import DataCon ( DataCon, dataConName ) -import Id ( Id, idPrimRep, idType ) +import Id ( Id, idPrimRep, idType, isDataConWrapId ) import Type ( typePrimRep ) import VarEnv import VarSet ( varSetElems ) -import Const ( Con(..), Literal ) +import Literal ( Literal ) import Maybes ( catMaybes, maybeToBool ) import Name ( isLocallyDefined, isWiredInName, NamedThing(..) ) #ifdef DEBUG import PprAbsC ( pprAmode ) #endif import PrimRep ( PrimRep(..) ) -import StgSyn ( StgArg, StgLiveVars, GenStgArg(..) ) +import StgSyn ( StgArg, StgLiveVars, GenStgArg(..), isStgTypeArg ) import Unique ( Unique, Uniquable(..) ) import UniqSet ( elementOfUniqSet ) import Util ( zipWithEqual, sortLt ) @@ -252,8 +252,13 @@ I {\em think} all looking-up is done through @getCAddrMode(s)@. getCAddrModeAndInfo :: Id -> FCode (CAddrMode, LambdaFormInfo) getCAddrModeAndInfo id - | not (isLocallyDefined name) || isWiredInName name - {- Why the "isWiredInName"? + | not (isLocallyDefined name) || isDataConWrapId id + -- Why the isDataConWrapId? Because CoreToStg changes a call to + -- a nullary constructor worker fn to a call to its wrapper, + -- which may not be defined until later + + {- -- OLD: the unpack stuff isn't injected now Jan 2000 + Why the "isWiredInName"? Imagine you are compiling PrelBase.hs (a module that supplies some of the wired-in values). What can happen is that the compiler will inject calls to @@ -342,6 +347,9 @@ getVolatileRegs vars getArgAmodes :: [StgArg] -> FCode [CAddrMode] getArgAmodes [] = returnFC [] getArgAmodes (atom:atoms) + | isStgTypeArg atom + = getArgAmodes atoms + | otherwise = getArgAmode atom `thenFC` \ amode -> getArgAmodes atoms `thenFC` \ amodes -> returnFC ( amode : amodes ) @@ -349,43 +357,7 @@ getArgAmodes (atom:atoms) getArgAmode :: StgArg -> FCode CAddrMode getArgAmode (StgVarArg var) = getCAddrMode var -- The common case - -getArgAmode (StgConArg (DataCon con)) - {- Why does this case differ from StgVarArg? - Because the program might look like this: - data Foo a = Empty | Baz a - f a x = let c = Empty! a - in h c - Now, when we go Core->Stg, we drop the type applications, - so we can inline c, giving - f x = h Empty - Now we are referring to Empty as an argument (rather than in an STGCon), - so we'll look it up with getCAddrMode. We want to return an amode for - the static closure that we make for nullary constructors. But if we blindly - go ahead with getCAddrMode we end up looking in the environment, and it ain't there! - - This special case used to be in getCAddrModeAndInfo, but it doesn't work there. - Consider: - f a x = Baz a x - If the constructor Baz isn't inlined we simply want to treat it like any other - identifier, with a top level definition. We don't want to spot that it's a constructor. - - In short - StgApp con args - and - StgCon con args - are treated differently; the former is a call to a bog standard function while the - latter uses the specially-labelled, pre-defined info tables etc for the constructor. - - The way to think of this case in getArgAmode is that - SApp f Empty - is really - App f (StgCon Empty []) - -} - = returnFC (CLbl (mkStaticClosureLabel (dataConName con)) PtrRep) - - -getArgAmode (StgConArg (Literal lit)) = returnFC (CLit lit) +getArgAmode (StgLitArg lit) = returnFC (CLit lit) \end{code} %************************************************************************ diff --git a/ghc/compiler/codeGen/CgCase.lhs b/ghc/compiler/codeGen/CgCase.lhs index e358b9bf55..9ede65019e 100644 --- a/ghc/compiler/codeGen/CgCase.lhs +++ b/ghc/compiler/codeGen/CgCase.lhs @@ -1,7 +1,7 @@ % % (c) The GRASP/AQUA Project, Glasgow University, 1992-1998 % -% $Id: CgCase.lhs,v 1.37 2000/01/13 14:33:57 hwloidl Exp $ +% $Id: CgCase.lhs,v 1.38 2000/03/23 17:45:19 simonpj Exp $ % %******************************************************** %* * @@ -49,12 +49,11 @@ import CLabel ( CLabel, mkVecTblLabel, mkReturnPtLabel, import ClosureInfo ( mkLFArgument ) import CmdLineOpts ( opt_SccProfilingOn, opt_GranMacros ) import CostCentre ( CostCentre ) -import CoreSyn ( isDeadBinder ) -import Id ( Id, idPrimRep ) +import Id ( Id, idPrimRep, isDeadBinder ) import DataCon ( DataCon, dataConTag, fIRST_TAG, ConTag, - isUnboxedTupleCon, dataConType ) + isUnboxedTupleCon ) import VarSet ( varSetElems ) -import Const ( Con(..), Literal ) +import Literal ( Literal ) import PrimOp ( primOpOutOfLine, PrimOp(..) ) import PrimRep ( getPrimRepSize, retPrimRepSize, PrimRep(..) ) @@ -150,7 +149,7 @@ mkBuiltinUnique, because that occasionally clashes with some temporaries generated for _ccall_GC, amongst others (see CgExpr.lhs). \begin{code} -cgCase (StgCon (PrimOp op) args res_ty) +cgCase (StgPrimApp op args res_ty) live_in_whole_case live_in_alts bndr srt (StgAlgAlts ty alts deflt) | isEnumerationTyCon tycon = getArgAmodes args `thenFC` \ arg_amodes -> @@ -197,7 +196,7 @@ cgCase (StgCon (PrimOp op) args res_ty) Special case #2: inline PrimOps. \begin{code} -cgCase (StgCon (PrimOp op) args res_ty) +cgCase (StgPrimApp op args res_ty) live_in_whole_case live_in_alts bndr srt alts | not (primOpOutOfLine op) = diff --git a/ghc/compiler/codeGen/CgCon.lhs b/ghc/compiler/codeGen/CgCon.lhs index 5fa258b359..f771fdb048 100644 --- a/ghc/compiler/codeGen/CgCon.lhs +++ b/ghc/compiler/codeGen/CgCon.lhs @@ -37,7 +37,7 @@ import Constants ( mAX_INTLIKE, mIN_INTLIKE, mIN_UPD_SIZE ) import CgHeapery ( allocDynClosure, inPlaceAllocDynClosure ) import CgTailCall ( performReturn, mkStaticAlgReturnCode, doTailCall, mkUnboxedTupleReturnCode ) -import CLabel ( mkClosureLabel, mkStaticClosureLabel ) +import CLabel ( mkClosureLabel ) import ClosureInfo ( mkClosureLFInfo, mkConLFInfo, mkLFArgument, layOutDynCon, layOutDynClosure, layOutStaticClosure, closureSize @@ -45,12 +45,12 @@ import ClosureInfo ( mkClosureLFInfo, mkConLFInfo, mkLFArgument, import CostCentre ( currentOrSubsumedCCS, dontCareCCS, CostCentreStack, currentCCS ) import DataCon ( DataCon, dataConName, dataConTag, dataConTyCon, - isUnboxedTupleCon ) -import MkId ( mkDataConId ) + isUnboxedTupleCon, isNullaryDataCon, isDynDataCon, dataConId, dataConWrapId + ) import Id ( Id, idName, idType, idPrimRep ) import Name ( nameModule, isLocallyDefinedName ) import Module ( isDynamicModule ) -import Const ( Con(..), Literal(..), isLitLitLit ) +import Literal ( Literal(..) ) import PrelInfo ( maybeCharLikeCon, maybeIntLikeCon ) import PrimRep ( PrimRep(..), isFollowableRep ) import Unique ( Uniquable(..) ) @@ -68,10 +68,9 @@ import Panic ( assertPanic, trace ) cgTopRhsCon :: Id -- Name of thing bound to this RHS -> DataCon -- Id -> [StgArg] -- Args - -> Bool -- All zero-size args (see buildDynCon) -> FCode (Id, CgIdInfo) -cgTopRhsCon id con args all_zero_size_args - = ASSERT(not (any_litlit_args || dynamic_con_or_args)) +cgTopRhsCon id con args + = ASSERT(not dynamic_con_or_args) -- checks for litlit args too ( -- LAY IT OUT getArgAmodes args `thenFC` \ amodes -> @@ -101,26 +100,7 @@ cgTopRhsCon id con args all_zero_size_args top_ccc = mkCCostCentreStack dontCareCCS -- because it's static data -- stuff needed by the assert pred only. - any_litlit_args = any isLitLitArg args - dynamic_con_or_args = dynamic_con || any (isDynamic) args - - dynamic_con = isDynName (dataConName con) - - isDynName nm = - not (isLocallyDefinedName nm) && - isDynamicModule (nameModule nm) - - {- - Do any of the arguments refer to something in a DLL? - -} - isDynamic (StgVarArg v) = isDynName (idName v) - isDynamic (StgConArg c) = - case c of - DataCon dc -> isDynName (dataConName dc) - Literal l -> isLitLitLit l -- all bets are off if it is. - _ -> False - - + dynamic_con_or_args = isDynDataCon con || any isDynArg args \end{code} %************************************************************************ @@ -137,13 +117,17 @@ buildDynCon :: Id -- Name of the thing to which this constr will -- current CCS if currentOrSubsumedCCS -> DataCon -- The data constructor -> [CAddrMode] -- Its args - -> Bool -- True <=> all args (if any) are - -- of "zero size" (i.e., VoidRep); - -- The reason we don't just look at the - -- args is that we may be in a "knot", and - -- premature looking at the args will cause - -- the compiler to black-hole! -> FCode CgIdInfo -- Return details about how to find it + +-- We used to pass a boolean indicating whether all the +-- args were of size zero, so we could use a static +-- construtor; but I concluded that it just isn't worth it. +-- Now I/O uses unboxed tuples there just aren't any constructors +-- with all size-zero args. +-- +-- The reason for having a separate argument, rather than looking at +-- the addr modes of the args is that we may be in a "knot", and +-- premature looking at the args will cause the compiler to black-hole! \end{code} First we deal with the case of zero-arity constructors. Now, they @@ -155,9 +139,9 @@ which have exclusively size-zero (VoidRep) args, we generate no code at all. \begin{code} -buildDynCon binder cc con args all_zero_size_args@True +buildDynCon binder cc con [] = returnFC (stableAmodeIdInfo binder - (CLbl (mkStaticClosureLabel (dataConName con)) PtrRep) + (CLbl (mkClosureLabel (idName (dataConWrapId con))) PtrRep) (mkConLFInfo con)) \end{code} @@ -177,7 +161,7 @@ which is guaranteed in range. Because of this, we use can safely return an addressing mode. \begin{code} -buildDynCon binder cc con [arg_amode] all_zero_size_args@False +buildDynCon binder cc con [arg_amode] | maybeCharLikeCon con = absC (CAssign temp_amode (CCharLike arg_amode)) `thenC` @@ -188,8 +172,8 @@ buildDynCon binder cc con [arg_amode] all_zero_size_args@False where (temp_amode, temp_id_info) = newTempAmodeAndIdInfo binder (mkConLFInfo con) - in_range_int_lit (CLit (MachInt val _)) = val <= mAX_INTLIKE && val >= mIN_INTLIKE - in_range_int_lit other_amode = False + in_range_int_lit (CLit (MachInt val)) = val <= mAX_INTLIKE && val >= mIN_INTLIKE + in_range_int_lit other_amode = False tycon = dataConTyCon con \end{code} @@ -197,7 +181,7 @@ buildDynCon binder cc con [arg_amode] all_zero_size_args@False Now the general case. \begin{code} -buildDynCon binder ccs con args all_zero_size_args@False +buildDynCon binder ccs con args = allocDynClosure closure_info use_cc blame_cc amodes_w_offsets `thenFC` \ hp_off -> returnFC (heapIdInfo binder hp_off lf_info) where @@ -283,9 +267,9 @@ bindUnboxedTupleComponents args Note: it's the responsibility of the @cgReturnDataCon@ caller to be sure the @amodes@ passed don't conflict with each other. \begin{code} -cgReturnDataCon :: DataCon -> [CAddrMode] -> Bool -> Code +cgReturnDataCon :: DataCon -> [CAddrMode] -> Code -cgReturnDataCon con amodes all_zero_size_args +cgReturnDataCon con amodes = getEndOfBlockInfo `thenFC` \ (EndOfBlockInfo args_sp sequel) -> case sequel of @@ -315,7 +299,7 @@ cgReturnDataCon con amodes all_zero_size_args -- If the sequel is an update frame, we might be able to -- do update in place... UpdateCode - | not all_zero_size_args -- no nullary constructors, please + | not (isNullaryDataCon con) -- no nullary constructors, please && not (maybeCharLikeCon con) -- no chars please (these are all static) && not (any isFollowableRep (map getAmodeRep amodes)) -- no ptrs please (generational gc...) @@ -394,17 +378,14 @@ cgReturnDataCon con amodes all_zero_size_args -- This Id is also used to get a unique for a -- temporary variable, if the closure is a CHARLIKE. - -- funilly enough, this makes the unique always come + -- funnily enough, this makes the unique always come -- out as '54' :-) - buildDynCon (mkDataConId con) currentCCS - con amodes all_zero_size_args - `thenFC` \ idinfo -> - idInfoToAmode PtrRep idinfo `thenFC` \ amode -> + buildDynCon (dataConId con) currentCCS con amodes `thenFC` \ idinfo -> + idInfoToAmode PtrRep idinfo `thenFC` \ amode -> -- RETURN profCtrC SLIT("TICK_RET_NEW") [mkIntCLit (length amodes)] `thenC` -- could use doTailCall here. performReturn (move_to_reg amode node) return - \end{code} diff --git a/ghc/compiler/codeGen/CgConTbls.lhs b/ghc/compiler/codeGen/CgConTbls.lhs index 7ae92a890d..a20e0ee097 100644 --- a/ghc/compiler/codeGen/CgConTbls.lhs +++ b/ghc/compiler/codeGen/CgConTbls.lhs @@ -14,14 +14,13 @@ import CgMonad import StgSyn ( SRT(..) ) import AbsCUtils ( mkAbstractCs, mkAbsCStmts ) import CgTailCall ( performReturn, mkStaticAlgReturnCode ) -import CLabel ( mkConEntryLabel, mkStaticClosureLabel ) +import CLabel ( mkConEntryLabel ) import ClosureInfo ( layOutStaticClosure, layOutDynCon, mkConLFInfo, ClosureInfo ) import CostCentre ( dontCareCCS ) import FiniteMap ( fmToList, FiniteMap ) -import DataCon ( DataCon, dataConName, dataConAllRawArgTys ) -import Const ( Con(..) ) +import DataCon ( DataCon, dataConName, dataConRepArgTys, isNullaryDataCon ) import Name ( getOccString ) import PrimRep ( getPrimRepSize, PrimRep(..) ) import TyCon ( tyConDataCons, isEnumerationTyCon, TyCon ) @@ -58,12 +57,9 @@ Static occurrences of the constructor macro: @STATIC_INFO_TABLE@. \end{description} -For zero-arity constructors, \tr{con}, we also generate a static closure: -\begin{description} -\item[@_closure@:] -A single static copy of the (zero-arity) constructor itself. -\end{description} +For zero-arity constructors, \tr{con}, we NO LONGER generate a static closure; +it's place is taken by the top level defn of the constructor. For charlike and intlike closures there is a fixed array of static closures predeclared. @@ -115,8 +111,7 @@ genConInfo comp_info tycon data_con = mkAbstractCs [ CSplitMarker, closure_code, - static_code, - closure_maybe] + static_code] -- Order of things is to reduce forward references where (closure_info, body_code) = mkConCodeAndInfo data_con @@ -144,26 +139,15 @@ genConInfo comp_info tycon data_con cost_centre = mkCCostCentreStack dontCareCCS -- not worried about static data costs - -- For zero-arity data constructors, or, more accurately, - -- those which only have VoidRep args (or none): - -- We make the closure too (not just info tbl), so that we can share - -- one copy throughout. - closure_maybe = if not zero_arity_con then - AbsCNop - else - CStaticClosure closure_label -- Label for closure - static_ci -- Info table - cost_centre - [{-No args! A slight lie for constrs - with VoidRep args-}] - zero_size arg_ty = getPrimRepSize (typePrimRep arg_ty) == 0 - zero_arity_con = all zero_size arg_tys + zero_arity_con = isNullaryDataCon data_con + -- We used to check that all the arg-sizes were zero, but we don't + -- really have any constructors with only zero-size args, and it's + -- just one more thing to go wrong. - arg_tys = dataConAllRawArgTys data_con + arg_tys = dataConRepArgTys data_con entry_label = mkConEntryLabel con_name - closure_label = mkStaticClosureLabel con_name con_name = dataConName data_con \end{code} @@ -173,7 +157,7 @@ mkConCodeAndInfo :: DataCon -- Data constructor mkConCodeAndInfo con = let - arg_tys = dataConAllRawArgTys con + arg_tys = dataConRepArgTys con (closure_info, arg_things) = layOutDynCon con typePrimRep arg_tys diff --git a/ghc/compiler/codeGen/CgExpr.lhs b/ghc/compiler/codeGen/CgExpr.lhs index 0fca2d3e57..78e8a300d4 100644 --- a/ghc/compiler/codeGen/CgExpr.lhs +++ b/ghc/compiler/codeGen/CgExpr.lhs @@ -1,7 +1,7 @@ % % (c) The GRASP/AQUA Project, Glasgow University, 1992-1998 % -% $Id: CgExpr.lhs,v 1.30 1999/10/25 13:21:16 sof Exp $ +% $Id: CgExpr.lhs,v 1.31 2000/03/23 17:45:19 simonpj Exp $ % %******************************************************** %* * @@ -40,9 +40,8 @@ import CostCentre ( sccAbleCostCentre, isSccCountCostCentre ) import Id ( idPrimRep, idType, Id ) import VarSet import DataCon ( DataCon, dataConTyCon ) -import Const ( Con(..) ) import IdInfo ( ArityInfo(..) ) -import PrimOp ( primOpOutOfLine, +import PrimOp ( primOpOutOfLine, ccallMayGC, getPrimOpResultInfo, PrimOp(..), PrimOpResultInfo(..) ) import PrimRep ( getPrimRepSize, PrimRep(..), isFollowableRep ) @@ -85,11 +84,9 @@ cgExpr (StgApp fun args) = cgTailCall fun args %******************************************************** \begin{code} -cgExpr (StgCon (DataCon con) args res_ty) +cgExpr (StgConApp con args) = getArgAmodes args `thenFC` \ amodes -> - cgReturnDataCon con amodes (all zero_size args) - where - zero_size atom = getPrimRepSize (getArgPrimRep atom) == 0 + cgReturnDataCon con amodes \end{code} Literals are similar to constructors; they return by putting @@ -97,9 +94,8 @@ themselves in an appropriate register and returning to the address on top of the stack. \begin{code} -cgExpr (StgCon (Literal lit) args res_ty) - = ASSERT( null args ) - performPrimReturn (text "literal" <+> ppr lit) (CLit lit) +cgExpr (StgLit lit) + = performPrimReturn (text "literal" <+> ppr lit) (CLit lit) \end{code} @@ -113,19 +109,21 @@ Here is where we insert real live machine instructions. NOTE about _ccall_GC_: -A _ccall_GC_ is treated as an out-of-line primop for the case -expression code, because we want a proper stack frame on the stack -when we perform it. When we get here, however, we need to actually -perform the call, so we treat it as an inline primop. +A _ccall_GC_ is treated as an out-of-line primop (returns True +for primOpOutOfLine) so that when we see the call in case context + case (ccall ...) of { ... } +we get a proper stack frame on the stack when we perform it. When we +get in a tail-call position, however, we need to actually perform the +call, so we treat it as an inline primop. \begin{code} -cgExpr (StgCon (PrimOp op@(CCallOp _ _ may_gc@True _)) args res_ty) +cgExpr (StgPrimApp op@(CCallOp ccall) args res_ty) = primRetUnboxedTuple op args res_ty -- tagToEnum# is special: we need to pull the constructor out of the table, -- and perform an appropriate return. -cgExpr (StgCon (PrimOp TagToEnumOp) [arg] res_ty) +cgExpr (StgPrimApp TagToEnumOp [arg] res_ty) = ASSERT(isEnumerationTyCon tycon) getArgAmode arg `thenFC` \amode -> -- save the tag in a temporary in case amode overlaps @@ -150,7 +148,7 @@ cgExpr (StgCon (PrimOp TagToEnumOp) [arg] res_ty) (Just (tycon,_)) = splitTyConApp_maybe res_ty -cgExpr x@(StgCon (PrimOp op) args res_ty) +cgExpr x@(StgPrimApp op args res_ty) | primOpOutOfLine op = tailCallPrimOp op args | otherwise = ASSERT(op /= SeqOp) -- can't handle SeqOp @@ -283,12 +281,9 @@ cgRhs :: Id -> StgRhs -> FCode (Id, CgIdInfo) -- the Id is passed along so a binding can be set up cgRhs name (StgRhsCon maybe_cc con args) - = getArgAmodes args `thenFC` \ amodes -> - buildDynCon name maybe_cc con amodes (all zero_size args) - `thenFC` \ idinfo -> + = getArgAmodes args `thenFC` \ amodes -> + buildDynCon name maybe_cc con amodes `thenFC` \ idinfo -> returnFC (name, idinfo) - where - zero_size atom = getPrimRepSize (getArgPrimRep atom) == 0 cgRhs name (StgRhsClosure cc bi srt@(NoSRT) fvs upd_flag args body) = mkRhsClosure name cc bi srt fvs upd_flag args body @@ -445,7 +440,7 @@ cgLetNoEscapeRhs full_live_in_rhss rhs_eob_info maybe_cc_slot rec binder (StgRhsCon cc con args) = cgLetNoEscapeClosure binder cc stgArgOcc{-safe-} NoSRT full_live_in_rhss rhs_eob_info maybe_cc_slot rec [] --No args; the binder is data structure, not a function - (StgCon (DataCon con) args (idType binder)) + (StgConApp con args) \end{code} Little helper for primitives that return unboxed tuples. @@ -478,5 +473,4 @@ primRetUnboxedTuple op args res_ty temp_amodes = zipWith CTemp temp_uniqs prim_reps in returnUnboxedTuple temp_amodes (absC (COpStmt temp_amodes op arg_temps [])) - \end{code} diff --git a/ghc/compiler/codeGen/CgRetConv.lhs b/ghc/compiler/codeGen/CgRetConv.lhs index d4784b6aae..a68a35287b 100644 --- a/ghc/compiler/codeGen/CgRetConv.lhs +++ b/ghc/compiler/codeGen/CgRetConv.lhs @@ -1,7 +1,7 @@ % % (c) The GRASP Project, Glasgow University, 1992-1998 % -% $Id: CgRetConv.lhs,v 1.19 1999/05/13 17:30:58 simonm Exp $ +% $Id: CgRetConv.lhs,v 1.20 2000/03/23 17:45:19 simonpj Exp $ % \section[CgRetConv]{Return conventions for the code generator} @@ -27,7 +27,7 @@ import CmdLineOpts ( opt_UseVanillaRegs, opt_UseFloatRegs, opt_UseDoubleRegs, opt_UseLongRegs ) import Maybes ( catMaybes ) -import DataCon ( dataConRawArgTys, DataCon ) +import DataCon ( DataCon ) import PrimOp ( PrimOp{-instance Outputable-} ) import PrimRep ( isFloatingRep, PrimRep(..), is64BitRep ) import TyCon ( TyCon, tyConDataCons, tyConFamilySize ) diff --git a/ghc/compiler/codeGen/CgTailCall.lhs b/ghc/compiler/codeGen/CgTailCall.lhs index 46e3b0219f..82c64a4c48 100644 --- a/ghc/compiler/codeGen/CgTailCall.lhs +++ b/ghc/compiler/codeGen/CgTailCall.lhs @@ -1,7 +1,7 @@ % % (c) The GRASP/AQUA Project, Glasgow University, 1992-1998 % -% $Id: CgTailCall.lhs,v 1.23 1999/11/02 15:05:43 simonmar Exp $ +% $Id: CgTailCall.lhs,v 1.24 2000/03/23 17:45:19 simonpj Exp $ % %******************************************************** %* * @@ -48,7 +48,7 @@ import ClosureInfo ( nodeMustPointToIt, import CmdLineOpts ( opt_DoSemiTagging ) import Id ( Id, idType, idName ) import DataCon ( DataCon, dataConTyCon, dataConTag, fIRST_TAG ) -import Const ( mkMachInt ) +import Literal ( mkMachInt ) import Maybes ( assocMaybe, maybeToBool ) import PrimRep ( PrimRep(..) ) import StgSyn ( StgArg, GenStgArg(..) ) diff --git a/ghc/compiler/codeGen/ClosureInfo.lhs b/ghc/compiler/codeGen/ClosureInfo.lhs index 157a6b70e2..62836a1d7b 100644 --- a/ghc/compiler/codeGen/ClosureInfo.lhs +++ b/ghc/compiler/codeGen/ClosureInfo.lhs @@ -1,7 +1,7 @@ % % (c) The GRASP/AQUA Project, Glasgow University, 1992-1998 % -% $Id: ClosureInfo.lhs,v 1.39 1999/11/02 15:05:44 simonmar Exp $ +% $Id: ClosureInfo.lhs,v 1.40 2000/03/23 17:45:19 simonpj Exp $ % \section[ClosureInfo]{Data structures which describe closures} @@ -67,7 +67,7 @@ import Constants ( mIN_UPD_SIZE, mIN_SIZE_NonUpdHeapObject, import CgRetConv ( assignRegs ) import CLabel ( CLabel, mkStdEntryLabel, mkFastEntryLabel, mkInfoTableLabel, - mkConInfoTableLabel, mkStaticClosureLabel, + mkConInfoTableLabel, mkCAFBlackHoleInfoTableLabel, mkSECAFBlackHoleInfoTableLabel, mkStaticInfoTableLabel, mkStaticConEntryLabel, @@ -79,7 +79,7 @@ import CLabel ( CLabel, mkStdEntryLabel, mkFastEntryLabel, import CmdLineOpts ( opt_SccProfilingOn, opt_OmitBlackHoling, opt_Parallel, opt_DoTickyProfiling, opt_SMP ) -import Id ( Id, idType, getIdArity ) +import Id ( Id, idType, idArityInfo ) import DataCon ( DataCon, dataConTag, fIRST_TAG, isNullaryDataCon, isTupleCon, dataConName ) @@ -258,7 +258,7 @@ mkLFLetNoEscape = LFLetNoEscape mkLFImported :: Id -> LambdaFormInfo mkLFImported id - = case getIdArity id of + = case idArityInfo id of ArityExactly 0 -> LFThunk (idType id) TopLevel True{-no fvs-} True{-updatable-} NonStandardThunk @@ -300,10 +300,8 @@ closurePtrsSize (MkClosureInfo _ _ sm_rep) -- not exported: sizes_from_SMRep :: SMRep -> (Int,Int) -sizes_from_SMRep (GenericRep ptrs nonptrs _) = (ptrs, nonptrs) -sizes_from_SMRep (StaticRep ptrs nonptrs _) = (ptrs, nonptrs) -sizes_from_SMRep ConstantRep = (0, 0) -sizes_from_SMRep BlackHoleRep = (0, 0) +sizes_from_SMRep (GenericRep _ ptrs nonptrs _) = (ptrs, nonptrs) +sizes_from_SMRep BlackHoleRep = (0, 0) \end{code} Computing slop size. WARNING: this looks dodgy --- it has deep @@ -341,16 +339,15 @@ slopSize cl_info@(MkClosureInfo _ lf_info sm_rep) computeSlopSize :: Int -> SMRep -> Bool -> Int -computeSlopSize tot_wds (StaticRep _ _ _) True -- Updatable +computeSlopSize tot_wds (GenericRep _ _ _ _) True -- Updatable = max 0 (mIN_UPD_SIZE - tot_wds) -computeSlopSize tot_wds (StaticRep _ _ _) False - = 0 -- non updatable, non-heap object -computeSlopSize tot_wds (GenericRep _ _ _) True -- Updatable - = max 0 (mIN_UPD_SIZE - tot_wds) -computeSlopSize tot_wds (GenericRep _ _ _) False - = max 0 (mIN_SIZE_NonUpdHeapObject - tot_wds) -computeSlopSize tot_wds ConstantRep _ - = 0 + +computeSlopSize tot_wds (GenericRep True _ _ _) False -- Non updatable + = 0 -- Static + +computeSlopSize tot_wds (GenericRep False _ _ _) False -- Non updatable + = max 0 (mIN_SIZE_NonUpdHeapObject - tot_wds) -- Dynamic + computeSlopSize tot_wds BlackHoleRep _ -- Updatable = max 0 (mIN_UPD_SIZE - tot_wds) \end{code} @@ -376,7 +373,7 @@ layOutDynClosure name kind_fn things lf_info where (tot_wds, -- #ptr_wds + #nonptr_wds ptr_wds, -- #ptr_wds - things_w_offsets) = mkVirtHeapOffsets sm_rep kind_fn things + things_w_offsets) = mkVirtHeapOffsets kind_fn things sm_rep = chooseDynSMRep lf_info tot_wds ptr_wds \end{code} @@ -407,25 +404,26 @@ layOutStaticNoFVClosure. \begin{code} layOutStaticClosure name kind_fn things lf_info = (MkClosureInfo name lf_info - (StaticRep ptr_wds (tot_wds - ptr_wds) closure_type), + (GenericRep is_static ptr_wds (tot_wds - ptr_wds) closure_type), things_w_offsets) where (tot_wds, -- #ptr_wds + #nonptr_wds ptr_wds, -- #ptr_wds - things_w_offsets) = mkVirtHeapOffsets (StaticRep bot bot bot) kind_fn things + things_w_offsets) = mkVirtHeapOffsets kind_fn things -- constructors with no pointer fields will definitely be NOCAF things. -- this is a compromise until we can generate both kinds of constructor -- (a normal static kind and the NOCAF_STATIC kind). - closure_type = case lf_info of - LFCon _ _ | ptr_wds == 0 -> CONSTR_NOCAF - _ -> getStaticClosureType lf_info + closure_type = getClosureType is_static tot_wds ptr_wds lf_info + is_static = True bot = panic "layoutStaticClosure" layOutStaticNoFVClosure :: Name -> LambdaFormInfo -> ClosureInfo layOutStaticNoFVClosure name lf_info - = MkClosureInfo name lf_info (StaticRep 0 0 (getStaticClosureType lf_info)) + = MkClosureInfo name lf_info (GenericRep is_static 0 0 (getClosureType is_static 0 0 lf_info)) + where + is_static = True \end{code} %************************************************************************ @@ -442,55 +440,45 @@ chooseDynSMRep chooseDynSMRep lf_info tot_wds ptr_wds = let - nonptr_wds = tot_wds - ptr_wds - closure_type = getClosureType tot_wds ptr_wds nonptr_wds lf_info + is_static = False + nonptr_wds = tot_wds - ptr_wds + closure_type = getClosureType is_static tot_wds ptr_wds lf_info in - case lf_info of - LFTuple _ True -> ConstantRep - LFCon _ True -> ConstantRep - _ -> GenericRep ptr_wds nonptr_wds closure_type - -getStaticClosureType :: LambdaFormInfo -> ClosureType -getStaticClosureType lf_info = - case lf_info of - LFCon con True -> CONSTR_NOCAF - LFCon con False -> CONSTR - LFReEntrant _ _ _ _ _ _ -> FUN - LFTuple _ _ -> CONSTR - LFThunk _ _ _ _ (SelectorThunk _) _ _ -> THUNK_SELECTOR - LFThunk _ _ _ True _ _ _ -> THUNK - LFThunk _ _ _ False _ _ _ -> FUN - _ -> panic "getClosureType" + GenericRep is_static ptr_wds nonptr_wds closure_type -- we *do* get non-updatable top-level thunks sometimes. eg. f = g -- gets compiled to a jump to g (if g has non-zero arity), instead of -- messing around with update frames and PAPs. We set the closure type -- to FUN_STATIC in this case. -getClosureType :: Int -> Int -> Int -> LambdaFormInfo -> ClosureType -getClosureType tot_wds ptrs nptrs lf_info = - case lf_info of - LFCon con True -> CONSTR_NOCAF +getClosureType :: Bool -> Int -> Int -> LambdaFormInfo -> ClosureType +getClosureType is_static tot_wds ptr_wds lf_info + = case lf_info of + LFCon con zero_arity + | is_static && ptr_wds == 0 -> CONSTR_NOCAF + | specialised_rep mAX_SPEC_CONSTR_SIZE -> CONSTR_p_n + | otherwise -> CONSTR - LFCon con False - | tot_wds > 0 && tot_wds <= mAX_SPEC_CONSTR_SIZE -> CONSTR_p_n ptrs nptrs - | otherwise -> CONSTR + LFTuple _ zero_arity + | is_static && ptr_wds == 0 -> CONSTR_NOCAF + | specialised_rep mAX_SPEC_CONSTR_SIZE -> CONSTR_p_n + | otherwise -> CONSTR LFReEntrant _ _ _ _ _ _ - | tot_wds > 0 && tot_wds <= mAX_SPEC_FUN_SIZE -> FUN_p_n ptrs nptrs - | otherwise -> FUN - - LFTuple _ _ - | tot_wds > 0 && tot_wds <= mAX_SPEC_CONSTR_SIZE -> CONSTR_p_n ptrs nptrs - | otherwise -> CONSTR + | specialised_rep mAX_SPEC_FUN_SIZE -> FUN_p_n + | otherwise -> FUN LFThunk _ _ _ _ (SelectorThunk _) _ _ -> THUNK_SELECTOR LFThunk _ _ _ _ _ _ _ - | tot_wds > 0 && tot_wds <= mAX_SPEC_THUNK_SIZE -> THUNK_p_n ptrs nptrs - | otherwise -> THUNK + | specialised_rep mAX_SPEC_THUNK_SIZE -> THUNK_p_n + | otherwise -> THUNK - _ -> panic "getClosureType" + _ -> panic "getClosureType" + where + specialised_rep max_size = not is_static + && tot_wds > 0 + && tot_wds <= max_size \end{code} %************************************************************************ @@ -504,8 +492,8 @@ smaller offsets than the unboxed things, and furthermore, the offsets in the result list \begin{code} -mkVirtHeapOffsets :: SMRep -- Representation to be used by storage manager - -> (a -> PrimRep) -- To be able to grab kinds; +mkVirtHeapOffsets :: + (a -> PrimRep) -- To be able to grab kinds; -- w/ a kind, we can find boxedness -> [a] -- Things to make offsets for -> (Int, -- *Total* number of words allocated @@ -516,7 +504,7 @@ mkVirtHeapOffsets :: SMRep -- Representation to be used by storage manager -- First in list gets lowest offset, which is initial offset + 1. -mkVirtHeapOffsets sm_rep kind_fun things +mkVirtHeapOffsets kind_fun things = let (ptrs, non_ptrs) = separateByPtrFollowness kind_fun things (wds_of_ptrs, ptrs_w_offsets) = mapAccumL computeOffset 0 ptrs (tot_wds, non_ptrs_w_offsets) = mapAccumL computeOffset wds_of_ptrs non_ptrs @@ -712,7 +700,10 @@ blackHoleOnEntry :: ClosureInfo -> Bool -- Single-entry ones have no fvs to plug, and we trust they don't form part -- of a loop. -blackHoleOnEntry (MkClosureInfo _ _ (StaticRep _ _ _)) = False +blackHoleOnEntry (MkClosureInfo _ _ rep) + | isStaticRep rep + = False + -- Never black-hole a static closure blackHoleOnEntry (MkClosureInfo _ lf_info _) = case lf_info of @@ -969,25 +960,18 @@ infoTableLabelFromCI (MkClosureInfo id lf_info rep) mkConInfoPtr :: DataCon -> SMRep -> CLabel mkConInfoPtr con rep - = case rep of - StaticRep _ _ _ -> mkStaticInfoTableLabel name - _ -> mkConInfoTableLabel name + | isStaticRep rep = mkStaticInfoTableLabel name + | otherwise = mkConInfoTableLabel name where name = dataConName con mkConEntryPtr :: DataCon -> SMRep -> CLabel mkConEntryPtr con rep - = case rep of - StaticRep _ _ _ -> mkStaticConEntryLabel (dataConName con) - _ -> mkConEntryLabel (dataConName con) + | isStaticRep rep = mkStaticConEntryLabel (dataConName con) + | otherwise = mkConEntryLabel (dataConName con) where name = dataConName con -closureLabelFromCI (MkClosureInfo name _ rep) - | isConstantRep rep - = mkStaticClosureLabel name - -- This case catches those pesky static closures for nullary constructors - closureLabelFromCI (MkClosureInfo id _ other_rep) = mkClosureLabel id entryLabelFromCI :: ClosureInfo -> CLabel diff --git a/ghc/compiler/codeGen/CodeGen.lhs b/ghc/compiler/codeGen/CodeGen.lhs index a2dcbc9bff..1f1d0f8e34 100644 --- a/ghc/compiler/codeGen/CodeGen.lhs +++ b/ghc/compiler/codeGen/CodeGen.lhs @@ -73,8 +73,11 @@ codeGen mod_name imported_modules cost_centre_info fe_binders cost_centre_info abstractC = mkAbstractCs [ init_stuff, - datatype_stuff, - code_stuff ] + code_stuff, + datatype_stuff] + -- Put datatype_stuff after code_stuff, because the + -- datatype closure table (for enumeration types) + -- to (say) PrelBase_True_closure, which is defined in code_stuff flat_abstractC = flattenAbsC fl_uniqs abstractC in @@ -221,9 +224,7 @@ cgTopRhs :: Id -> StgRhs -> FCode (Id, CgIdInfo) -- the Id is passed along for setting up a binding... cgTopRhs bndr (StgRhsCon cc con args) - = forkStatics (cgTopRhsCon bndr con args (all zero_size args)) - where - zero_size atom = getPrimRepSize (getArgPrimRep atom) == 0 + = forkStatics (cgTopRhsCon bndr con args) cgTopRhs bndr (StgRhsClosure cc bi srt fvs upd_flag args body) = ASSERT(null fvs) -- There should be no free variables diff --git a/ghc/compiler/codeGen/SMRep.lhs b/ghc/compiler/codeGen/SMRep.lhs index aabcf40449..c338cf8b3f 100644 --- a/ghc/compiler/codeGen/SMRep.lhs +++ b/ghc/compiler/codeGen/SMRep.lhs @@ -9,7 +9,7 @@ Other modules should access this info through ClosureInfo. \begin{code} module SMRep ( SMRep(..), ClosureType(..), - isConstantRep, isStaticRep, + isStaticRep, fixedHdrSize, arrWordsHdrSize, arrPtrsHdrSize, fixedItblSize, pprSMRep @@ -68,31 +68,28 @@ import GlaExts ( Int(..), Int#, (<#), (==#), (<#), (>#) ) \begin{code} data SMRep -- static closure have an extra static link field at the end. - = StaticRep - Int -- # ptr words (useful for interpreter, debugger, etc) - Int -- # non-ptr words - ClosureType -- closure type - - | GenericRep -- GC routines consult sizes in info tbl + = GenericRep -- GC routines consult sizes in info tbl + Bool -- True <=> This is a static closure. Affects how + -- we garbage-collect it Int -- # ptr words Int -- # non-ptr words ClosureType -- closure type - | ConstantRep -- CONSTR with zero-arity - | BlackHoleRep -data ClosureType +data ClosureType -- Corresponds 1-1 with the varieties of closures + -- implemented by the RTS. Compare with ghc/includes/ClosureTypes.h = CONSTR - | CONSTR_p_n Int Int + | CONSTR_p_n -- The p_n variants have more efficient GC, but we + -- only provide them for dynamically-allocated closures + -- (We could do them for static ones, but we don't) | CONSTR_NOCAF | FUN - | FUN_p_n Int Int + | FUN_p_n | THUNK - | THUNK_p_n Int Int + | THUNK_p_n | THUNK_SELECTOR deriving (Eq,Ord) - \end{code} Size of a closure header. @@ -140,77 +137,63 @@ tickyItblSize | opt_DoTickyProfiling = tICKY_ITBL_SIZE \end{code} \begin{code} -isConstantRep, isStaticRep :: SMRep -> Bool -isConstantRep ConstantRep = True -isConstantRep other = False - -isStaticRep (StaticRep _ _ _) = True -isStaticRep _ = False +isStaticRep :: SMRep -> Bool +isStaticRep (GenericRep is_static _ _ _) = is_static +isStaticRep BlackHoleRep = False \end{code} \begin{code} -{- ToDo: needed? -} -instance Text SMRep where - showsPrec d rep - = showString (case rep of - StaticRep _ _ _ -> "STATIC" - GenericRep _ _ _ -> "" - ConstantRep -> "") - instance Outputable SMRep where ppr rep = pprSMRep rep pprSMRep :: SMRep -> SDoc -pprSMRep (GenericRep _ _ t) = pprClosureType t -pprSMRep (StaticRep _ _ t) = pprClosureType t <> ptext SLIT("_STATIC") -pprSMRep ConstantRep = ptext SLIT("CONSTR_NOCAF_STATIC") -pprSMRep BlackHoleRep = ptext SLIT("BLACKHOLE") - -pprClosureType CONSTR = ptext SLIT("CONSTR") -pprClosureType (CONSTR_p_n p n) = ptext SLIT("CONSTR_") <> int p <> char '_' <> int n -pprClosureType CONSTR_NOCAF = ptext SLIT("CONSTR_NOCAF") -pprClosureType FUN = ptext SLIT("FUN") -pprClosureType (FUN_p_n p n) = ptext SLIT("FUN_") <> int p <> char '_' <> int n -pprClosureType THUNK = ptext SLIT("THUNK") -pprClosureType (THUNK_p_n p n) = ptext SLIT("THUNK_") <> int p <> char '_' <> int n -pprClosureType THUNK_SELECTOR = ptext SLIT("THUNK_SELECTOR") +pprSMRep (GenericRep True ptrs nptrs clo_ty) = pprClosureType clo_ty ptrs nptrs <> ptext SLIT("_STATIC") +pprSMRep (GenericRep False ptrs nptrs clo_ty) = pprClosureType clo_ty ptrs nptrs + +pprClosureType CONSTR p n = ptext SLIT("CONSTR") +pprClosureType CONSTR_p_n p n = ptext SLIT("CONSTR_") <> int p <> char '_' <> int n +pprClosureType CONSTR_NOCAF p n = ptext SLIT("CONSTR_NOCAF") +pprClosureType FUN p n = ptext SLIT("FUN") +pprClosureType FUN_p_n p n = ptext SLIT("FUN_") <> int p <> char '_' <> int n +pprClosureType THUNK p n = ptext SLIT("THUNK") +pprClosureType THUNK_p_n p n = ptext SLIT("THUNK_") <> int p <> char '_' <> int n +pprClosureType THUNK_SELECTOR p n = ptext SLIT("THUNK_SELECTOR") #ifndef OMIT_NATIVE_CODEGEN getSMRepClosureTypeInt :: SMRep -> Int -getSMRepClosureTypeInt (GenericRep _ _ t) = - case t of - CONSTR -> cONSTR - CONSTR_p_n 1 0 -> cONSTR_1_0 - CONSTR_p_n 0 1 -> cONSTR_0_1 - CONSTR_p_n 2 0 -> cONSTR_2_0 - CONSTR_p_n 1 1 -> cONSTR_1_1 - CONSTR_p_n 0 2 -> cONSTR_0_2 - CONSTR_NOCAF -> panic "getClosureTypeInt: CONSTR_NOCAF" - FUN -> fUN - FUN_p_n 1 0 -> fUN_1_0 - FUN_p_n 0 1 -> fUN_0_1 - FUN_p_n 2 0 -> fUN_2_0 - FUN_p_n 1 1 -> fUN_1_1 - FUN_p_n 0 2 -> fUN_0_2 - THUNK -> tHUNK - THUNK_p_n 1 0 -> tHUNK_1_0 - THUNK_p_n 0 1 -> tHUNK_0_1 - THUNK_p_n 2 0 -> tHUNK_2_0 - THUNK_p_n 1 1 -> tHUNK_1_1 - THUNK_p_n 0 2 -> tHUNK_0_2 - THUNK_SELECTOR -> tHUNK_SELECTOR -getSMRepClosureTypeInt (StaticRep _ _ t) = - case t of - CONSTR -> cONSTR_STATIC - CONSTR_NOCAF -> cONSTR_NOCAF_STATIC - FUN -> fUN_STATIC - THUNK -> tHUNK_STATIC - THUNK_SELECTOR -> panic "getClosureTypeInt: THUNK_SELECTOR_STATIC" - -getSMRepClosureTypeInt ConstantRep = cONSTR_NOCAF_STATIC +getSMRepClosureTypeInt (GenericRep False _ _ CONSTR) = cONSTR +getSMRepClosureTypeInt (GenericRep False 1 0 CONSTR_p_n) = cONSTR_1_0 +getSMRepClosureTypeInt (GenericRep False 0 1 CONSTR_p_n) = cONSTR_0_1 +getSMRepClosureTypeInt (GenericRep False 2 0 CONSTR_p_n) = cONSTR_2_0 +getSMRepClosureTypeInt (GenericRep False 1 1 CONSTR_p_n) = cONSTR_1_1 +getSMRepClosureTypeInt (GenericRep False 0 2 CONSTR_p_n) = cONSTR_0_2 + +getSMRepClosureTypeInt (GenericRep False _ _ FUN) = fUN +getSMRepClosureTypeInt (GenericRep False 1 0 FUN_p_n) = fUN_1_0 +getSMRepClosureTypeInt (GenericRep False 0 1 FUN_p_n) = fUN_0_1 +getSMRepClosureTypeInt (GenericRep False 2 0 FUN_p_n) = fUN_2_0 +getSMRepClosureTypeInt (GenericRep False 1 1 FUN_p_n) = fUN_1_1 +getSMRepClosureTypeInt (GenericRep False 0 2 FUN_p_n) = fUN_0_2 + +getSMRepClosureTypeInt (GenericRep False _ _ THUNK) = tHUNK +getSMRepClosureTypeInt (GenericRep False 1 0 THUNK_p_n) = tHUNK_1_0 +getSMRepClosureTypeInt (GenericRep False 0 1 THUNK_p_n) = tHUNK_0_1 +getSMRepClosureTypeInt (GenericRep False 2 0 THUNK_p_n) = tHUNK_2_0 +getSMRepClosureTypeInt (GenericRep False 1 1 THUNK_p_n) = tHUNK_1_1 +getSMRepClosureTypeInt (GenericRep False 0 2 THUNK_p_n) = tHUNK_0_2 + +getSMRepClosureTypeInt (GenericRep False _ _ THUNK_SELECTOR) = tHUNK_SELECTOR + +getSMRepClosureTypeInt (GenericRep True _ _ CONSTR) = cONSTR_STATIC +getSMRepClosureTypeInt (GenericRep True _ _ CONSTR_NOCAF) = cONSTR_NOCAF_STATIC +getSMRepClosureTypeInt (GenericRep True _ _ FUN) = fUN_STATIC +getSMRepClosureTypeInt (GenericRep True _ _ THUNK) = tHUNK_STATIC getSMRepClosureTypeInt BlackHoleRep = bLACKHOLE +getSMRepClosureTypeInt rep = pprPanic "getSMRepClosureTypeInt:" (pprSMRep rep) + + -- Just the ones we need: #include "../includes/ClosureTypes.h" |