2 {-# LANGUAGE OverloadedStrings #-}
3 {-# LANGUAGE ForeignFunctionInterface #-}
4 module Mate.ClassPool (
17 import qualified Data.Map as M
18 import qualified Data.Set as S
19 import qualified Data.ByteString.Lazy as B
27 import Foreign.C.Types
28 import Foreign.Marshal.Alloc
33 import Mate.BasicBlocks
34 import {-# SOURCE #-} Mate.MethodPool
38 getClassInfo :: B.ByteString -> IO ClassInfo
39 getClassInfo path = do
40 class_map <- get_classmap >>= ptr2classmap
41 case M.lookup path class_map of
42 Nothing -> loadAndInitClass path
45 getClassFile :: B.ByteString -> IO (Class Resolved)
46 getClassFile path = do
47 ci <- getClassInfo path
50 getStaticFieldOffset :: B.ByteString -> B.ByteString -> IO (CUInt)
51 getStaticFieldOffset path field = do
52 ci <- getClassInfo path
53 return $ fromIntegral $ (ciStaticMap ci) M.! field
55 getFieldOffset :: B.ByteString -> B.ByteString -> IO (Int32)
56 getFieldOffset path field = do
57 ci <- getClassInfo path
58 return $ (ciFieldMap ci) M.! field
60 -- method + signature plz!
61 getMethodOffset :: B.ByteString -> B.ByteString -> IO (Word32)
62 getMethodOffset path method = do
63 ci <- getClassInfo path
64 return $ fromIntegral $ (ciMethodMap ci) M.! method
66 getMethodTable :: B.ByteString -> IO (Word32)
67 getMethodTable path = do
68 ci <- getClassInfo path
69 return $ ciMethodBase ci
71 getObjectSize :: B.ByteString -> IO (Word32)
72 getObjectSize path = do
73 ci <- getClassInfo path
74 -- TODO(bernhard): correct sizes for different types...
75 let fsize = fromIntegral $ M.size $ ciFieldMap ci
76 -- one slot for "method-table-ptr"
77 return $ (1 + fsize) * 4
79 foreign export ccall getStaticFieldAddr :: CUInt -> Ptr () -> IO CUInt
80 getStaticFieldAddr :: CUInt -> Ptr () -> IO CUInt
81 getStaticFieldAddr from ptr_trapmap = do
82 trapmap <- ptr2trapmap ptr_trapmap
83 let w32_from = fromIntegral from
84 let sfi = trapmap M.! w32_from
86 (SFI (StaticFieldInfo cls field)) -> do
87 getStaticFieldOffset cls field
88 _ -> error $ "getFieldAddr: no trapInfo. abort"
90 loadClass :: B.ByteString -> IO ClassInfo
93 printf "loadClass: \"%s\"\n" $ toString path
95 let rpath = toString $ path `B.append` ".class"
96 cfile <- parseClassFile rpath
97 superclass <- case (path /= "java/lang/Object") of
99 sc <- loadClass $ superClass cfile
101 False -> return $ Nothing
103 (staticmap, fieldmap) <- calculateFields cfile superclass
104 (methodmap, mbase) <- calculateMethodMap cfile superclass
106 printf "staticmap: %s @ %s\n" (show staticmap) (toString path)
107 printf "fieldmap: %s @ %s\n" (show fieldmap) (toString path)
108 printf "methodmap: %s @ %s\n" (show methodmap) (toString path)
109 printf "mbase: 0x%08x\n" mbase
112 virtual_map <- get_virtualmap >>= ptr2virtualmap
113 let virtual_map' = M.insert mbase path virtual_map
114 virtualmap2ptr virtual_map' >>= set_virtualmap
116 class_map <- get_classmap >>= ptr2classmap
117 let new_ci = ClassInfo path cfile staticmap fieldmap methodmap mbase False
118 let class_map' = M.insert path new_ci class_map
119 classmap2ptr class_map' >>= set_classmap
123 calculateFields :: Class Resolved -> Maybe ClassInfo -> IO (FieldMap, FieldMap)
124 calculateFields cf superclass = do
125 -- TODO(bernhard): correct sizes. int only atm
127 let (sfields, ifields) = span (S.member ACC_STATIC . fieldAccessFlags) (classFields cf)
129 staticbase <- mallocBytes ((fromIntegral $ length sfields) * 4)
130 let i_sb = fromIntegral $ ptrToIntPtr $ staticbase
131 let sm = zipbase i_sb sfields
132 let sc_sm = getsupermap superclass ciStaticMap
133 -- new fields "overwrite" old ones, if they have the same name
134 let staticmap = (M.fromList sm) `M.union` sc_sm
136 let sc_im = getsupermap superclass ciFieldMap
137 -- "+ 4" for the method table pointer
138 let max_off = (fromIntegral $ (M.size sc_im) * 4) + 4
139 let im = zipbase max_off ifields
140 -- new fields "overwrite" old ones, if they have the same name
141 let fieldmap = (M.fromList im) `M.union` sc_im
143 return (staticmap, fieldmap)
145 zipbase base = zipWith (\x y -> (fieldName y, x + base)) [0,4..]
148 getsupermap :: Maybe ClassInfo -> (ClassInfo -> FieldMap) -> FieldMap
149 getsupermap superclass getter = case superclass of Just x -> getter x; Nothing -> M.empty
152 calculateMethodMap :: Class Resolved -> Maybe ClassInfo -> IO (FieldMap, Word32)
153 calculateMethodMap cf superclass = do
155 (\x -> (not . S.member ACC_STATIC . methodAccessFlags) x &&
156 ((/=) "<init>" . methodName) x)
158 let sc_mm = getsupermap superclass ciMethodMap
159 let max_off = fromIntegral $ (M.size sc_mm) * 4
160 let mm = zipbase max_off methods
161 let methodmap = (M.fromList mm) `M.union` sc_mm
163 methodbase <- mallocBytes ((fromIntegral $ M.size methodmap) * 4)
164 return (methodmap, fromIntegral $ ptrToIntPtr $ methodbase)
165 where zipbase base = zipWith (\x y -> (entry y, x + base)) [0,4..]
166 where entry y = (methodName y) `B.append` (encode $ methodSignature y)
169 loadAndInitClass :: B.ByteString -> IO ClassInfo
170 loadAndInitClass path = do
171 class_map <- get_classmap >>= ptr2classmap
172 ci <- case M.lookup path class_map of
173 Nothing -> loadClass path
176 -- first try to execute class initializer of superclass
177 when (path /= "java/lang/Object") ((loadAndInitClass $ superClass $ ciFile ci) >> return ())
179 -- execute class initializer
180 case lookupMethod "<clinit>" (ciFile ci) of
182 hmap <- parseMethod (ciFile ci) "<clinit>"
185 let mi = (MethodInfo "<clinit>" path (methodSignature m))
186 entry <- compileBB hmap' mi
187 addMethodRef entry mi [path]
189 printf "executing static initializer from %s now\n" (toString path)
193 printf "static initializer from %s done\n" (toString path)
195 Nothing -> error $ "loadClass: static initializer not found (WTF?). abort"
198 class_map' <- get_classmap >>= ptr2classmap
199 let new_ci = ci { ciInitDone = True }
200 let class_map'' = M.insert path new_ci class_map'
201 classmap2ptr class_map'' >>= set_classmap