1 {-# LANGUAGE RecordWildCards, BangPatterns #-}
2 module JVM.ClassFile where
5 import Control.Applicative
7 import Data.Binary.IEEE754
12 import qualified Data.ByteString.Lazy as B
16 traceS :: (Show a) => String -> a -> a
17 traceS msg x = trace (msg ++ ": " ++ show x) x
20 char n = chr (fromIntegral n)
27 data ClassFile = ClassFile {
29 minorVersion :: Word16,
30 majorVersion :: Word16,
31 constsPoolSize :: Word16,
32 constsPool :: [CpInfo],
33 accessFlags :: Word16,
36 interfacesCount :: Word16,
37 interfaces :: [Word16],
38 classFieldsCount :: Word16,
39 classFields :: [FieldInfo],
40 classMethodsCount :: Word16,
41 classMethods :: [MethodInfo],
42 classAttributesCount :: Word16,
43 classAttributes :: [AttributeInfo]
51 replicateMT n m = replicateM n (traceM ">" m)
53 instance Binary ClassFile where
54 put (ClassFile {..}) = do
68 forM_ classMethods put
69 put classAttributesCount
70 forM_ classAttributes put
77 pool <- replicateM (fromIntegral poolsize - 1) get
81 interfacesCount <- get
82 ifaces <- replicateM (fromIntegral interfacesCount) get
83 classFieldsCount <- get
84 classFields <- replicateM (fromIntegral classFieldsCount) get
85 classMethodsCount <- get
86 classMethods <- replicateM (fromIntegral classMethodsCount) get
88 as <- replicateM (fromIntegral $ asCount - 1) get
89 return $ ClassFile magic minor major poolsize pool af this super
90 interfacesCount ifaces classFieldsCount classFields classMethodsCount classMethods asCount as
101 | ObjectType String -- L <class name>
102 | Array (Maybe Int) FieldType
105 type FieldSignature = FieldType
107 getInt :: Get (Maybe Int)
112 else return $ Just (read s)
114 getDigits :: Get [Char]
116 c <- lookAhead getChar8
124 instance Binary FieldType where
125 put SignedByte = put 'B'
126 put CharByte = put 'C'
127 put DoubleType = put 'D'
128 put FloatType = put 'F'
129 put IntType = put 'I'
130 put LongInt = put 'J'
131 put ShortInt = put 'S'
132 put BoolType = put 'Z'
133 put (ObjectType name) = put 'L' >> put name
134 put (Array Nothing sig) = put '[' >> put sig
135 put (Array (Just n) sig) = put '[' >> put (show n) >> put sig
140 'B' -> return SignedByte
141 'C' -> return CharByte
142 'D' -> return DoubleType
143 'F' -> return FloatType
144 'I' -> return IntType
145 'J' -> return LongInt
146 'S' -> return ShortInt
147 'Z' -> return BoolType
149 name <- getToSemicolon
150 return (ObjectType name)
154 return (Array mbSize sig)
155 _ -> fail $ "Unknown signature opening symbol: " ++ [b]
157 getToSemicolon :: Get String
163 next <- getToSemicolon
166 data ReturnSignature =
171 instance Binary ReturnSignature where
172 put (Returns sig) = put sig
173 put ReturnsVoid = put 'V'
176 x <- lookAhead getChar8
178 'V' -> skip 1 >> return ReturnsVoid
181 type ArgumentSignature = FieldType
183 data MethodSignature =
184 MethodSignature [ArgumentSignature] ReturnSignature
187 instance Binary MethodSignature where
188 put (MethodSignature args ret) = do
197 fail "Cannot parse method signature: no starting `(' !"
201 fail "Internal error: method signature without `)' !?"
203 return (MethodSignature args ret)
205 getArgs :: Get [ArgumentSignature]
206 getArgs = whileJust getArg
208 getArg :: Get (Maybe ArgumentSignature)
210 x <- lookAhead getChar8
215 whileJust :: (Monad m) => m (Maybe a) -> m [a]
225 CONSTANT_Class {nameIndex :: Word16} -- 7
226 | CONSTANT_Fieldref {classIndex :: Word16, nameAndTypeIndex :: Word16} -- 9
227 | CONSTANT_Methodref {classIndex :: Word16, nameAndTypeIndex :: Word16} -- 10
228 | CONSTANT_InterfaceMethodref {classIndex :: Word16, nameAndTypeIndex :: Word16}-- 11
229 | CONSTANT_String {stringIndex :: Word16} -- 8
230 | CONSTANT_Integer {fourBytes :: Word32} -- 3
231 | CONSTANT_Float Float -- 4
232 | CONSTANT_Long Word64 -- 5
233 | CONSTANT_Double Double -- 6
234 | CONSTANT_NameAndType {nameIndex :: Word16, signatureIndex :: Word16} -- 12
235 | CONSTANT_Utf8 {stringLength :: Word16, stringBytes :: B.ByteString} -- 1
236 | CONSTANT_Unicode {stringLength :: Word16, stringBytes :: B.ByteString} -- 2
239 instance Binary CpInfo where
240 put (CONSTANT_Class i) = putWord8 7 >> put i
241 put (CONSTANT_Fieldref i j) = putWord8 9 >> put i >> put j
242 put (CONSTANT_Methodref i j) = putWord8 10 >> put i >> put j
243 put (CONSTANT_InterfaceMethodref i j) = putWord8 11 >> put i >> put j
244 put (CONSTANT_String i) = putWord8 8 >> put i
245 put (CONSTANT_Integer x) = putWord8 3 >> put x
246 put (CONSTANT_Float x) = putWord8 4 >> putFloat32be x
247 put (CONSTANT_Long x) = putWord8 5 >> put x
248 put (CONSTANT_Double x) = putWord8 6 >> putFloat64be x
249 put (CONSTANT_NameAndType i j) = putWord8 12 >> put i >> put j
250 put (CONSTANT_Utf8 l bs) = putWord8 1 >> put l >> putLazyByteString bs
251 put (CONSTANT_Unicode l bs) = putWord8 2 >> put l >> putLazyByteString bs
259 bs <- getLazyByteString (fromIntegral l)
260 return $ CONSTANT_Utf8 l bs
263 bs <- getLazyByteString (fromIntegral l)
264 return $ CONSTANT_Unicode l bs
265 3 -> CONSTANT_Integer <$> get
266 4 -> CONSTANT_Float <$> getFloat32be
267 5 -> CONSTANT_Long <$> get
268 6 -> CONSTANT_Double <$> getFloat64be
269 7 -> CONSTANT_Class <$> get
270 8 -> CONSTANT_String <$> get
271 9 -> CONSTANT_Fieldref <$> get <*> get
272 10 -> CONSTANT_Methodref <$> get <*> get
273 11 -> CONSTANT_InterfaceMethodref <$> get <*> get
274 12 -> CONSTANT_NameAndType <$> get <*> get
275 _ -> fail $ "Unknown constants pool entry tag: " ++ show tag
277 data FieldInfo = FieldInfo {
278 fieldAccessFlags :: Word16,
279 fieldNameIndex :: Word16,
280 fieldSignatureIndex :: Word16,
281 fieldAttributesCount :: Word16,
282 fieldAttributes :: [AttributeInfo] }
285 instance Binary FieldInfo where
286 put (FieldInfo {..}) = do
289 put fieldSignatureIndex
290 put fieldAttributesCount
291 forM_ fieldAttributes put
298 as <- replicateM (fromIntegral n) get
299 return $ FieldInfo af ni si n as
301 data MethodInfo = MethodInfo {
302 methodAccessFlags :: Word16,
303 methodNameIndex :: Word16,
304 methodSignatureIndex :: Word16,
305 methodAttributesCount :: Word16,
306 methodAttributes :: [AttributeInfo] }
309 instance Binary MethodInfo where
310 put (MethodInfo {..}) = do
311 put methodAccessFlags
313 put methodSignatureIndex
314 put methodAttributesCount
315 forM_ methodAttributes put
323 as <- replicateM (fromIntegral n) get
324 return $ MethodInfo af ni si n as
326 data AttributeInfo = AttributeInfo {
327 attributeName :: Word16,
328 attributeLength :: Word32,
329 attributeValue :: B.ByteString }
332 instance Binary AttributeInfo where
333 put (AttributeInfo {..}) = do
335 putWord32be attributeLength
336 putLazyByteString attributeValue
342 value <- getLazyByteString (fromIntegral len)
343 return $ AttributeInfo name len value