1 {-# LANGUAGE RecordWildCards, BangPatterns #-}
2 module JVM.ClassFile where
5 import Control.Applicative
7 import Data.Binary.IEEE754
13 import qualified Data.ByteString.Lazy as B
17 traceS :: (Show a) => String -> a -> a
18 traceS msg x = trace (msg ++ ": " ++ show x) x
21 char n = chr (fromIntegral n)
28 data ClassFile = ClassFile {
30 minorVersion :: Word16,
31 majorVersion :: Word16,
32 constsPoolSize :: Word16,
33 constsPool :: [CpInfo],
34 accessFlags :: Word16,
37 interfacesCount :: Word16,
38 interfaces :: [Word16],
39 classFieldsCount :: Word16,
40 classFields :: [FieldInfo],
41 classMethodsCount :: Word16,
42 classMethods :: [MethodInfo],
43 classAttributesCount :: Word16,
44 classAttributes :: [AttributeInfo]
52 replicateMT n m = replicateM n (traceM ">" m)
54 instance Binary ClassFile where
55 put (ClassFile {..}) = do
69 forM_ classMethods put
70 put classAttributesCount
71 forM_ classAttributes put
78 pool <- replicateM (fromIntegral poolsize - 1) get
82 interfacesCount <- get
83 ifaces <- replicateM (fromIntegral interfacesCount) get
84 classFieldsCount <- get
85 classFields <- replicateM (fromIntegral classFieldsCount) get
86 classMethodsCount <- get
87 classMethods <- replicateM (fromIntegral classMethodsCount) get
89 as <- replicateM (fromIntegral $ asCount - 1) get
90 return $ ClassFile magic minor major poolsize pool af this super
91 interfacesCount ifaces classFieldsCount classFields classMethodsCount classMethods asCount as
102 | ObjectType String -- L <class name>
103 | Array (Maybe Int) FieldType
106 instance Show FieldType where
107 show SignedByte = "byte"
108 show CharByte = "char"
109 show DoubleType = "double"
110 show FloatType = "float"
112 show LongInt = "long"
113 show ShortInt = "short"
114 show BoolType = "bool"
115 show (ObjectType s) = "Object " ++ s
116 show (Array Nothing t) = show t ++ "[]"
117 show (Array (Just n) t) = show t ++ "[" ++ show n ++ "]"
119 type FieldSignature = FieldType
121 getInt :: Get (Maybe Int)
126 else return $ Just (read s)
128 getDigits :: Get [Char]
130 c <- lookAhead getChar8
138 instance Binary FieldType where
139 put SignedByte = put 'B'
140 put CharByte = put 'C'
141 put DoubleType = put 'D'
142 put FloatType = put 'F'
143 put IntType = put 'I'
144 put LongInt = put 'J'
145 put ShortInt = put 'S'
146 put BoolType = put 'Z'
147 put (ObjectType name) = put 'L' >> put name
148 put (Array Nothing sig) = put '[' >> put sig
149 put (Array (Just n) sig) = put '[' >> put (show n) >> put sig
154 'B' -> return SignedByte
155 'C' -> return CharByte
156 'D' -> return DoubleType
157 'F' -> return FloatType
158 'I' -> return IntType
159 'J' -> return LongInt
160 'S' -> return ShortInt
161 'Z' -> return BoolType
163 name <- getToSemicolon
164 return (ObjectType name)
168 return (Array mbSize sig)
169 _ -> fail $ "Unknown signature opening symbol: " ++ [b]
171 getToSemicolon :: Get String
177 next <- getToSemicolon
180 data ReturnSignature =
185 instance Show ReturnSignature where
186 show (Returns t) = show t
187 show ReturnsVoid = "Void"
189 instance Binary ReturnSignature where
190 put (Returns sig) = put sig
191 put ReturnsVoid = put 'V'
194 x <- lookAhead getChar8
196 'V' -> skip 1 >> return ReturnsVoid
199 type ArgumentSignature = FieldType
201 data MethodSignature =
202 MethodSignature [ArgumentSignature] ReturnSignature
205 instance Show MethodSignature where
206 show (MethodSignature args ret) = "(" ++ intercalate ", " (map show args) ++ ") returns " ++ show ret
208 instance Binary MethodSignature where
209 put (MethodSignature args ret) = do
218 fail "Cannot parse method signature: no starting `(' !"
222 fail "Internal error: method signature without `)' !?"
224 return (MethodSignature args ret)
226 getArgs :: Get [ArgumentSignature]
227 getArgs = whileJust getArg
229 getArg :: Get (Maybe ArgumentSignature)
231 x <- lookAhead getChar8
236 whileJust :: (Monad m) => m (Maybe a) -> m [a]
246 CONSTANT_Class {nameIndex :: Word16} -- 7
247 | CONSTANT_Fieldref {classIndex :: Word16, nameAndTypeIndex :: Word16} -- 9
248 | CONSTANT_Methodref {classIndex :: Word16, nameAndTypeIndex :: Word16} -- 10
249 | CONSTANT_InterfaceMethodref {classIndex :: Word16, nameAndTypeIndex :: Word16}-- 11
250 | CONSTANT_String {stringIndex :: Word16} -- 8
251 | CONSTANT_Integer {fourBytes :: Word32} -- 3
252 | CONSTANT_Float Float -- 4
253 | CONSTANT_Long Word64 -- 5
254 | CONSTANT_Double Double -- 6
255 | CONSTANT_NameAndType {nameIndex :: Word16, signatureIndex :: Word16} -- 12
256 | CONSTANT_Utf8 {stringLength :: Word16, stringBytes :: B.ByteString} -- 1
257 | CONSTANT_Unicode {stringLength :: Word16, stringBytes :: B.ByteString} -- 2
260 instance Binary CpInfo where
261 put (CONSTANT_Class i) = putWord8 7 >> put i
262 put (CONSTANT_Fieldref i j) = putWord8 9 >> put i >> put j
263 put (CONSTANT_Methodref i j) = putWord8 10 >> put i >> put j
264 put (CONSTANT_InterfaceMethodref i j) = putWord8 11 >> put i >> put j
265 put (CONSTANT_String i) = putWord8 8 >> put i
266 put (CONSTANT_Integer x) = putWord8 3 >> put x
267 put (CONSTANT_Float x) = putWord8 4 >> putFloat32be x
268 put (CONSTANT_Long x) = putWord8 5 >> put x
269 put (CONSTANT_Double x) = putWord8 6 >> putFloat64be x
270 put (CONSTANT_NameAndType i j) = putWord8 12 >> put i >> put j
271 put (CONSTANT_Utf8 l bs) = putWord8 1 >> put l >> putLazyByteString bs
272 put (CONSTANT_Unicode l bs) = putWord8 2 >> put l >> putLazyByteString bs
280 bs <- getLazyByteString (fromIntegral l)
281 return $ CONSTANT_Utf8 l bs
284 bs <- getLazyByteString (fromIntegral l)
285 return $ CONSTANT_Unicode l bs
286 3 -> CONSTANT_Integer <$> get
287 4 -> CONSTANT_Float <$> getFloat32be
288 5 -> CONSTANT_Long <$> get
289 6 -> CONSTANT_Double <$> getFloat64be
290 7 -> CONSTANT_Class <$> get
291 8 -> CONSTANT_String <$> get
292 9 -> CONSTANT_Fieldref <$> get <*> get
293 10 -> CONSTANT_Methodref <$> get <*> get
294 11 -> CONSTANT_InterfaceMethodref <$> get <*> get
295 12 -> CONSTANT_NameAndType <$> get <*> get
296 _ -> fail $ "Unknown constants pool entry tag: " ++ show tag
298 data FieldInfo = FieldInfo {
299 fieldAccessFlags :: Word16,
300 fieldNameIndex :: Word16,
301 fieldSignatureIndex :: Word16,
302 fieldAttributesCount :: Word16,
303 fieldAttributes :: [AttributeInfo] }
306 instance Binary FieldInfo where
307 put (FieldInfo {..}) = do
310 put fieldSignatureIndex
311 put fieldAttributesCount
312 forM_ fieldAttributes put
319 as <- replicateM (fromIntegral n) get
320 return $ FieldInfo af ni si n as
322 data MethodInfo = MethodInfo {
323 methodAccessFlags :: Word16,
324 methodNameIndex :: Word16,
325 methodSignatureIndex :: Word16,
326 methodAttributesCount :: Word16,
327 methodAttributes :: [AttributeInfo] }
330 instance Binary MethodInfo where
331 put (MethodInfo {..}) = do
332 put methodAccessFlags
334 put methodSignatureIndex
335 put methodAttributesCount
336 forM_ methodAttributes put
344 as <- replicateM (fromIntegral n) get
345 return $ MethodInfo af ni si n as
347 data AttributeInfo = AttributeInfo {
348 attributeName :: Word16,
349 attributeLength :: Word32,
350 attributeValue :: B.ByteString }
353 instance Binary AttributeInfo where
354 put (AttributeInfo {..}) = do
356 putWord32be attributeLength
357 putLazyByteString attributeValue
363 value <- getLazyByteString (fromIntegral len)
364 return $ AttributeInfo name len value