X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=compiler%2Fghci%2FByteCodeGen.lhs;h=b4d026a9f45799068916526e9bce61113e8d205e;hb=59e99f059c3b3f235fa12f19f15544ebf022f35b;hp=444fe873152939fa05bad11013d6cdaf0860afc5;hpb=568e6b65ac52a2bcdb0450cc265f52080f78ab08;p=ghc-hetmet.git diff --git a/compiler/ghci/ByteCodeGen.lhs b/compiler/ghci/ByteCodeGen.lhs index 444fe87..b4d026a 100644 --- a/compiler/ghci/ByteCodeGen.lhs +++ b/compiler/ghci/ByteCodeGen.lhs @@ -5,15 +5,23 @@ ByteCodeGen: Generate bytecode from Core \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 ByteCodeGen ( UnlinkedBCO, byteCodeGen, coreExprToBCOs ) where #include "HsVersions.h" import ByteCodeInstr import ByteCodeItbls -import ByteCodeFFI import ByteCodeAsm import ByteCodeLink +import ByteCodeFFI +import LibFFI import Outputable import Name @@ -48,8 +56,7 @@ import OrdList import Constants import Data.List ( intersperse, sortBy, zip4, zip6, partition ) -import Foreign ( Ptr, castPtr, mallocBytes, pokeByteOff, Word8, - withForeignPtr, castFunPtrToPtr, nullPtr, plusPtr ) +import Foreign import Foreign.C import Control.Exception ( throwDyn ) @@ -103,7 +110,7 @@ coreExprToBCOs dflags expr -- create a totally bogus name for the top-level BCO; this -- should be harmless, since it's never used for anything - let invented_name = mkSystemVarName (mkPseudoUniqueE 0) FSLIT("ExprTopLevel") + let invented_name = mkSystemVarName (mkPseudoUniqueE 0) (fsLit "ExprTopLevel") invented_id = Id.mkLocalId invented_name (panic "invented_id's type") -- the uniques are needed to generate fresh variables when we introduce new @@ -171,17 +178,19 @@ mkProtoBCO nm instrs_ordlist origin arity bitmap_size bitmap is_ret mallocd_bloc -- (hopefully rare) cases when the (overestimated) stack use -- exceeds iNTERP_STACK_CHECK_THRESH. maybe_with_stack_check - | is_ret = peep_d - -- don't do stack checks at return points; + | is_ret && stack_usage < aP_STACK_SPLIM = peep_d + -- don't do stack checks at return points, -- everything is aggregated up to the top BCO - -- (which must be a function) - | stack_overest >= iNTERP_STACK_CHECK_THRESH - = STKCHECK stack_overest : peep_d + -- (which must be a function). + -- That is, unless the stack usage is >= AP_STACK_SPLIM, + -- see bug #1466. + | stack_usage >= iNTERP_STACK_CHECK_THRESH + = STKCHECK stack_usage : peep_d | otherwise = peep_d -- the supposedly common case -- We assume that this sum doesn't wrap - stack_overest = sum (map bciStackUse peep_d) + stack_usage = sum (map bciStackUse peep_d) -- Merge local pushes peep_d = peep (fromOL instrs_ordlist) @@ -418,9 +427,15 @@ schemeE d s p (AnnLet binds (_,body)) return (push_code `appOL` more_push_code) alloc_code = toOL (zipWith mkAlloc sizes arities) - where mkAlloc sz 0 = ALLOC_AP sz + where mkAlloc sz 0 + | is_tick = ALLOC_AP_NOUPD sz + | otherwise = ALLOC_AP sz mkAlloc sz arity = ALLOC_PAP arity sz + is_tick = case binds of + AnnNonRec id _ -> occNameFS (getOccName id) == tickFS + _other -> False + compile_bind d' fvs x rhs size arity off = do bco <- schemeR fvs (x,rhs) build_thunk d' fvs size bco off arity @@ -435,18 +450,24 @@ schemeE d s p (AnnLet binds (_,body)) thunk_codes <- sequence compile_binds return (alloc_code `appOL` concatOL thunk_codes `appOL` body_code) --- introduce a let binding for a ticked case expression. This rule *should* only fire when the --- expression was not already let-bound (the code gen for let bindings should take care of that). --- Todo: we call exprFreeVars on a deAnnotated expression, this may not be the best way --- to calculate the free vars but it seemed like the least intrusive thing to do +-- introduce a let binding for a ticked case expression. This rule +-- *should* only fire when the expression was not already let-bound +-- (the code gen for let bindings should take care of that). Todo: we +-- call exprFreeVars on a deAnnotated expression, this may not be the +-- best way to calculate the free vars but it seemed like the least +-- intrusive thing to do schemeE d s p exp@(AnnCase {}) - | Just (tickInfo, _exp) <- isTickedExp' exp = do - let fvs = exprFreeVars $ deAnnotate' exp - let ty = exprType $ deAnnotate' exp - id <- newId ty - -- Todo: is emptyVarSet correct on the next line? - let letExp = AnnLet (AnnNonRec id (fvs, exp)) (emptyVarSet, AnnVar id) - schemeE d s p letExp + | Just (tickInfo,rhs) <- isTickedExp' exp + = if isUnLiftedType ty + then schemeE d s p (snd rhs) + else do + id <- newId ty + -- Todo: is emptyVarSet correct on the next line? + let letExp = AnnLet (AnnNonRec id (fvs, exp)) (emptyVarSet, AnnVar id) + schemeE d s p letExp + where exp' = deAnnotate' exp + fvs = exprFreeVars exp' + ty = exprType exp' schemeE d s p (AnnCase scrut bndr _ [(DataAlt dc, [bind1, bind2], rhs)]) | isUnboxedTupleCon dc, VoidArg <- typeCgRep (idType bind1) @@ -911,18 +932,18 @@ generateCCall d0 s p ccall_spec@(CCallSpec target cconv safety) fn args_r_to_l | t == arrayPrimTyCon || t == mutableArrayPrimTyCon -> do rest <- pargs (d + addr_sizeW) az code <- parg_ArrayishRep arrPtrsHdrSize d p a - return ((code,NonPtrArg):rest) + return ((code,AddrRep):rest) | t == byteArrayPrimTyCon || t == mutableByteArrayPrimTyCon -> do rest <- pargs (d + addr_sizeW) az code <- parg_ArrayishRep arrWordsHdrSize d p a - return ((code,NonPtrArg):rest) + return ((code,AddrRep):rest) -- Default case: push taggedly, but otherwise intact. other -> do (code_a, sz_a) <- pushAtom d p a rest <- pargs (d+sz_a) az - return ((code_a, atomRep a) : rest) + return ((code_a, atomPrimRep a) : rest) -- Do magic for Ptr/Byte arrays. Push a ptr to the array on -- the stack but then advance it over the headers, so as to @@ -939,9 +960,9 @@ generateCCall d0 s p ccall_spec@(CCallSpec target cconv safety) fn args_r_to_l (pushs_arg, a_reps_pushed_r_to_l) = unzip code_n_reps push_args = concatOL pushs_arg - d_after_args = d0 + sum (map cgRepSizeW a_reps_pushed_r_to_l) + d_after_args = d0 + sum (map primRepSizeW a_reps_pushed_r_to_l) a_reps_pushed_RAW - | null a_reps_pushed_r_to_l || head a_reps_pushed_r_to_l /= VoidArg + | null a_reps_pushed_r_to_l || head a_reps_pushed_r_to_l /= VoidRep = panic "ByteCodeGen.generateCCall: missing or invalid World token?" | otherwise = reverse (tail a_reps_pushed_r_to_l) @@ -953,7 +974,7 @@ generateCCall d0 s p ccall_spec@(CCallSpec target cconv safety) fn args_r_to_l -- Get the result rep. (returns_void, r_rep) = case maybe_getCCallReturnRep (idType fn) of - Nothing -> (True, VoidArg) + Nothing -> (True, VoidRep) Just rr -> (False, rr) {- Because the Haskell stack grows down, the a_reps refer to @@ -1019,7 +1040,7 @@ generateCCall d0 s p ccall_spec@(CCallSpec target cconv safety) fn args_r_to_l -- Push the return placeholder. For a call returning nothing, -- this is a VoidArg (tag). - r_sizeW = cgRepSizeW r_rep + r_sizeW = primRepSizeW r_rep d_after_r = d_after_Addr + r_sizeW r_lit = mkDummyLiteral r_rep push_r = (if returns_void @@ -1031,24 +1052,28 @@ generateCCall d0 s p ccall_spec@(CCallSpec target cconv safety) fn args_r_to_l addr_offW = r_sizeW arg1_offW = r_sizeW + addr_sizeW args_offW = map (arg1_offW +) - (init (scanl (+) 0 (map cgRepSizeW a_reps))) - -- in - addr_of_marshaller <- ioToBc (mkMarshalCode cconv - (r_offW, r_rep) addr_offW - (zip args_offW a_reps)) - recordItblMallocBc (ItblPtr (castFunPtrToPtr addr_of_marshaller)) - let + (init (scanl (+) 0 (map primRepSizeW a_reps))) + -- Offset of the next stack frame down the stack. The CCALL -- instruction needs to describe the chunk of stack containing -- the ccall args to the GC, so it needs to know how large it -- is. See comment in Interpreter.c with the CCALL instruction. stk_offset = d_after_r - s + -- in + -- the only difference in libffi mode is that we prepare a cif + -- describing the call type by calling libffi, and we attach the + -- address of this to the CCALL instruction. + token <- ioToBc $ prepForeignCall cconv a_reps r_rep + let addr_of_marshaller = castPtrToFunPtr token + + recordItblMallocBc (ItblPtr (castFunPtrToPtr addr_of_marshaller)) + let -- do the call do_call = unitOL (CCALL stk_offset (castFunPtrToPtr addr_of_marshaller)) -- slide and return wrapup = mkSLIDE r_sizeW (d_after_r - r_sizeW - s) - `snocOL` RETURN_UBX r_rep + `snocOL` RETURN_UBX (primRepToCgRep r_rep) --in --trace (show (arg1_offW, args_offW , (map cgRepSizeW a_reps) )) $ return ( @@ -1056,17 +1081,19 @@ generateCCall d0 s p ccall_spec@(CCallSpec target cconv safety) fn args_r_to_l push_Addr `appOL` push_r `appOL` do_call `appOL` wrapup ) - -- Make a dummy literal, to be used as a placeholder for FFI return -- values on the stack. -mkDummyLiteral :: CgRep -> Literal +mkDummyLiteral :: PrimRep -> Literal mkDummyLiteral pr = case pr of - NonPtrArg -> MachWord 0 - DoubleArg -> MachDouble 0 - FloatArg -> MachFloat 0 - LongArg -> MachWord64 0 - _ -> moan64 "mkDummyLiteral" (ppr pr) + IntRep -> MachInt 0 + WordRep -> MachWord 0 + AddrRep -> MachNullAddr + DoubleRep -> MachDouble 0 + FloatRep -> MachFloat 0 + Int64Rep -> MachInt64 0 + Word64Rep -> MachWord64 0 + _ -> panic "mkDummyLiteral" -- Convert (eg) @@ -1083,21 +1110,21 @@ mkDummyLiteral pr -- -- to Nothing -maybe_getCCallReturnRep :: Type -> Maybe CgRep +maybe_getCCallReturnRep :: Type -> Maybe PrimRep maybe_getCCallReturnRep fn_ty = let (a_tys, r_ty) = splitFunTys (dropForAlls fn_ty) maybe_r_rep_to_go = if isSingleton r_reps then Nothing else Just (r_reps !! 1) (r_tycon, r_reps) = case splitTyConApp_maybe (repType r_ty) of - (Just (tyc, tys)) -> (tyc, map typeCgRep tys) + (Just (tyc, tys)) -> (tyc, map typePrimRep tys) Nothing -> blargh - ok = ( ( r_reps `lengthIs` 2 && VoidArg == head r_reps) - || r_reps == [VoidArg] ) + ok = ( ( r_reps `lengthIs` 2 && VoidRep == head r_reps) + || r_reps == [VoidRep] ) && isUnboxedTupleTyCon r_tycon && case maybe_r_rep_to_go of Nothing -> True - Just r_rep -> r_rep /= PtrArg + Just r_rep -> r_rep /= PtrRep -- if it was, it would be impossible -- to create a valid return value -- placeholder on the stack @@ -1370,13 +1397,14 @@ lookupBCEnv_maybe = lookupFM idSizeW :: Id -> Int idSizeW id = cgRepSizeW (typeCgRep (idType id)) +-- See bug #1257 unboxedTupleException :: a unboxedTupleException = throwDyn - (Panic - ("Bytecode generator can't handle unboxed tuples. Possibly due\n" ++ - "\tto foreign import/export decls in source. Workaround:\n" ++ - "\tcompile this module to a .o file, then restart session.")) + (ProgramError + ("Error: bytecode compiler can't handle unboxed tuples.\n"++ + " Possibly due to foreign import/export decls in source.\n"++ + " Workaround: use -fobject-code, or compile this module to .o separately.")) mkSLIDE n d = if d == 0 then nilOL else unitOL (SLIDE n d) @@ -1398,19 +1426,22 @@ isTypeAtom (AnnType _) = True isTypeAtom _ = False isVoidArgAtom :: AnnExpr' id ann -> Bool -isVoidArgAtom (AnnVar v) = typeCgRep (idType v) == VoidArg +isVoidArgAtom (AnnVar v) = typePrimRep (idType v) == VoidRep isVoidArgAtom (AnnNote n (_,e)) = isVoidArgAtom e isVoidArgAtom (AnnCast (_,e) _) = isVoidArgAtom e isVoidArgAtom _ = False +atomPrimRep :: AnnExpr' Id ann -> PrimRep +atomPrimRep (AnnVar v) = typePrimRep (idType v) +atomPrimRep (AnnLit l) = typePrimRep (literalType l) +atomPrimRep (AnnNote n b) = atomPrimRep (snd b) +atomPrimRep (AnnApp f (_, AnnType _)) = atomPrimRep (snd f) +atomPrimRep (AnnLam x e) | isTyVar x = atomPrimRep (snd e) +atomPrimRep (AnnCast b _) = atomPrimRep (snd b) +atomPrimRep other = pprPanic "atomPrimRep" (ppr (deAnnotate (undefined,other))) + atomRep :: AnnExpr' Id ann -> CgRep -atomRep (AnnVar v) = typeCgRep (idType v) -atomRep (AnnLit l) = typeCgRep (literalType l) -atomRep (AnnNote n b) = atomRep (snd b) -atomRep (AnnApp f (_, AnnType _)) = atomRep (snd f) -atomRep (AnnLam x e) | isTyVar x = atomRep (snd e) -atomRep (AnnCast b _) = atomRep (snd b) -atomRep other = pprPanic "atomRep" (ppr (deAnnotate (undefined,other))) +atomRep e = primRepToCgRep (atomPrimRep e) isPtrAtom :: AnnExpr' Id ann -> Bool isPtrAtom e = atomRep e == PtrArg @@ -1503,5 +1534,7 @@ newUnique = BcM $ newId :: Type -> BcM Id newId ty = do uniq <- newUnique - return $ mkSysLocal FSLIT("ticked") uniq ty + return $ mkSysLocal tickFS uniq ty + +tickFS = fsLit "ticked" \end{code}