From bffffc890bdfb5b3d9bd23383da5ade093befba6 Mon Sep 17 00:00:00 2001 From: Ilya Portnov Date: Sat, 1 Oct 2011 21:27:45 +0600 Subject: [PATCH] Documentation attempt. --- JVM/Assembler.hs | 3 +- JVM/Builder/Instructions.hs | 132 +++++++++++++++++++++++++++++++++++- JVM/Builder/Monad.hs | 52 +++++++++++--- JVM/Common.hs | 10 ++- JVM/Dump.hs | 1 + Java/IO.hs | 4 ++ Java/Lang.hs | 10 +++ 7 files changed, 200 insertions(+), 12 deletions(-) diff --git a/JVM/Assembler.hs b/JVM/Assembler.hs index db036db..b47c4cc 100644 --- a/JVM/Assembler.hs +++ b/JVM/Assembler.hs @@ -116,7 +116,7 @@ readInstructions = do next <- readInstructions return (x: next) --- | JVM instruction set +-- | JVM instruction set. For comments, see JVM specification. data Instruction = NOP -- ^ 0 | ACONST_NULL -- ^ 1 @@ -708,6 +708,7 @@ instance BinaryState Integer Instruction where | inRange (159, 164) c -> IF_ICMP (toEnum $ fromIntegral $ c-159) <$> get | otherwise -> fail $ "Unknown instruction byte code: " ++ show c +-- | Encode list of instructions encodeInstructions :: [Instruction] -> B.ByteString encodeInstructions code = let p list = forM_ list put diff --git a/JVM/Builder/Instructions.hs b/JVM/Builder/Instructions.hs index 3eec20f..a9c8221 100644 --- a/JVM/Builder/Instructions.hs +++ b/JVM/Builder/Instructions.hs @@ -1,162 +1,292 @@ - +-- | This module exports shortcuts for some of JVM instructions (which are defined in JVM.Assembler). module JVM.Builder.Instructions where +import Data.Word +import qualified Data.ByteString.Lazy as B + import JVM.ClassFile import JVM.Assembler import JVM.Builder.Monad +nop :: Generate () nop = i0 NOP +aconst_null :: Generate () aconst_null = i0 ACONST_NULL +iconst_m1 :: Generate () iconst_m1 = i0 ICONST_M1 +iconst_0 :: Generate () iconst_0 = i0 ICONST_0 +iconst_1 :: Generate () iconst_1 = i0 ICONST_1 +iconst_2 :: Generate () iconst_2 = i0 ICONST_2 +iconst_3 :: Generate () iconst_3 = i0 ICONST_3 +iconst_4 :: Generate () iconst_4 = i0 ICONST_4 +iconst_5 :: Generate () iconst_5 = i0 ICONST_5 +lconst_0 :: Generate () lconst_0 = i0 LCONST_0 +lconst_1 :: Generate () lconst_1 = i0 LCONST_1 +fconst_0 :: Generate () fconst_0 = i0 FCONST_0 +fconst_1 :: Generate () fconst_1 = i0 FCONST_1 +fconst_2 :: Generate () fconst_2 = i0 FCONST_2 +dconst_0 :: Generate () dconst_0 = i0 DCONST_0 +dconst_1 :: Generate () dconst_1 = i0 DCONST_1 +bipush :: Word8 -> Generate () bipush x = i0 (BIPUSH x) +sipush :: Word16 -> Generate () sipush x = i0 (SIPUSH x) +ldc1 :: Constant Resolved -> Generate () ldc1 x = i8 LDC1 x +ldc2 :: Constant Resolved -> Generate () ldc2 x = i1 LDC2 x +ldc2w :: Constant Resolved -> Generate () ldc2w x = i1 LDC2W x +iload :: Constant Resolved -> Generate () iload x = i8 ILOAD x +lload :: Constant Resolved -> Generate () lload x = i8 LLOAD x +fload :: Constant Resolved -> Generate () fload x = i8 FLOAD x +dload :: Constant Resolved -> Generate () dload x = i8 DLOAD x +aload :: Constant Resolved -> Generate () aload x = i8 ALOAD x +iload_ :: IMM -> Generate () iload_ x = i0 (ILOAD_ x) +lload_ :: IMM -> Generate () lload_ x = i0 (LLOAD_ x) +fload_ :: IMM -> Generate () fload_ x = i0 (FLOAD_ x) +dload_ :: IMM -> Generate () dload_ x = i0 (DLOAD_ x) +aload_ :: IMM -> Generate () aload_ x = i0 (ALOAD_ x) +iaload :: Generate () iaload = i0 IALOAD +laload :: Generate () laload = i0 LALOAD +faload :: Generate () faload = i0 FALOAD +daload :: Generate () daload = i0 DALOAD +aaload :: Generate () aaload = i0 AALOAD +caload :: Generate () caload = i0 CALOAD +saload :: Generate () saload = i0 SALOAD +istore :: Constant Resolved -> Generate () istore x = i8 ISTORE x +lstore :: Constant Resolved -> Generate () lstore x = i8 LSTORE x +fstore :: Constant Resolved -> Generate () fstore x = i8 FSTORE x +dstore :: Constant Resolved -> Generate () dstore x = i8 DSTORE x +astore :: Constant Resolved -> Generate () astore x = i8 ASTORE x +istore_ :: Word8 -> Generate () istore_ x = i0 (ISTORE x) +lstore_ :: Word8 -> Generate () lstore_ x = i0 (LSTORE x) +fstore_ :: Word8 -> Generate () fstore_ x = i0 (FSTORE x) +dstore_ :: Word8 -> Generate () dstore_ x = i0 (DSTORE x) +astore_ :: Word8 -> Generate () astore_ x = i0 (ASTORE x) +iastore :: Generate () iastore = i0 IASTORE +lastore :: Generate () lastore = i0 LASTORE +fastore :: Generate () fastore = i0 FASTORE +dastore :: Generate () dastore = i0 DASTORE +aastore :: Generate () aastore = i0 AASTORE +bastore :: Generate () bastore = i0 BASTORE +castore :: Generate () castore = i0 CASTORE +sastore :: Generate () sastore = i0 SASTORE +pop :: Generate () pop = i0 POP +pop2 :: Generate () pop2 = i0 POP2 +dup :: Generate () dup = i0 DUP +dup_x1 :: Generate () dup_x1 = i0 DUP_X1 +dup_x2 :: Generate () dup_x2 = i0 DUP_X2 +dup2 :: Generate () dup2 = i0 DUP2 +dup2_x1 :: Generate () dup2_x1 = i0 DUP2_X1 +dup2_x2 :: Generate () dup2_x2 = i0 DUP2_X2 +swap :: Generate () swap = i0 SWAP +iadd :: Generate () iadd = i0 IADD +ladd :: Generate () ladd = i0 LADD +fadd :: Generate () fadd = i0 FADD +dadd :: Generate () dadd = i0 DADD +isub :: Generate () isub = i0 ISUB +lsub :: Generate () lsub = i0 LSUB +fsub :: Generate () fsub = i0 FSUB +dsub :: Generate () dsub = i0 DSUB +imul :: Generate () imul = i0 IMUL +lmul :: Generate () lmul = i0 LMUL +fmul :: Generate () fmul = i0 FMUL +dmul :: Generate () dmul = i0 DMUL +idiv :: Generate () idiv = i0 IDIV +ldiv :: Generate () ldiv = i0 LDIV +fdiv :: Generate () fdiv = i0 FDIV +ddiv :: Generate () ddiv = i0 DDIV +irem :: Generate () irem = i0 IREM +lrem :: Generate () lrem = i0 LREM +frem :: Generate () frem = i0 FREM +drem :: Generate () drem = i0 DREM +ineg :: Generate () ineg = i0 INEG +lneg :: Generate () lneg = i0 LNEG +fneg :: Generate () fneg = i0 FNEG +dneg :: Generate () dneg = i0 DNEG +ishl :: Generate () ishl = i0 ISHL +lshl :: Generate () lshl = i0 LSHL +ishr :: Generate () ishr = i0 ISHR +lshr :: Generate () lshr = i0 LSHR +iushr :: Generate () iushr = i0 IUSHR +lushr :: Generate () lushr = i0 LUSHR +iand :: Generate () iand = i0 IAND +land :: Generate () land = i0 LAND +ior :: Generate () ior = i0 IOR +lor :: Generate () lor = i0 LOR +ixor :: Generate () ixor = i0 IXOR +lxor :: Generate () lxor = i0 LXOR +iinc :: Word8 -> Word8 -> Generate () iinc x y = i0 (IINC x y) +i2l :: Generate () i2l = i0 I2L +i2f :: Generate () i2f = i0 I2F +i2d :: Generate () i2d = i0 I2D +l2i :: Generate () l2i = i0 L2I +l2f :: Generate () l2f = i0 L2F +l2d :: Generate () l2d = i0 L2D +f2i :: Generate () f2i = i0 F2I +f2l :: Generate () f2l = i0 F2L +f2d :: Generate () f2d = i0 F2D +d2i :: Generate () d2i = i0 D2I +d2l :: Generate () d2l = i0 D2L +d2f :: Generate () d2f = i0 D2F +i2b :: Generate () i2b = i0 I2B +i2c :: Generate () i2c = i0 I2C +i2s :: Generate () i2s = i0 I2S +lcmp :: Generate () lcmp = i0 LCMP +new :: B.ByteString -> Generate () new cls = i1 NEW (CClass cls) +newArray :: ArrayType -> Generate () newArray t = i0 (NEWARRAY $ atype2byte t) +allocNewArray :: B.ByteString -> Generate () allocNewArray cls = i1 ANEWARRAY (CClass cls) +invokeVirtual :: B.ByteString -> NameType Method -> Generate () invokeVirtual cls sig = i1 INVOKEVIRTUAL (CMethod cls sig) +invokeStatic :: B.ByteString -> NameType Method -> Generate () invokeStatic cls sig = i1 INVOKESTATIC (CMethod cls sig) +invokeSpecial :: B.ByteString -> NameType Method -> Generate () invokeSpecial cls sig = i1 INVOKESPECIAL (CMethod cls sig) +getStaticField :: B.ByteString -> NameType Field -> Generate () getStaticField cls sig = i1 GETSTATIC (CField cls sig) +loadString :: B.ByteString -> Generate () loadString str = i8 LDC1 (CString str) +allocArray :: B.ByteString -> Generate () allocArray cls = i1 ANEWARRAY (CClass cls) diff --git a/JVM/Builder/Monad.hs b/JVM/Builder/Monad.hs index 2ab3f7a..2d4a290 100644 --- a/JVM/Builder/Monad.hs +++ b/JVM/Builder/Monad.hs @@ -1,5 +1,16 @@ {-# LANGUAGE FlexibleContexts, TypeFamilies, OverloadedStrings #-} -module JVM.Builder.Monad where +-- | This module defines Generate monad, which helps generating JVM code and +-- creating Java class constants pool. +module JVM.Builder.Monad + (GState (..), + emptyGState, + Generate, + addToPool, + i0, i1, i8, + newMethod, + setStackSize, setMaxLocals, + generate + ) where import Control.Monad.State as St import Data.Word @@ -13,15 +24,19 @@ import JVM.Common () -- import instances only import JVM.ClassFile import JVM.Assembler +-- | Generator state data GState = GState { - generated :: [Instruction], - currentPool :: Pool Resolved, - doneMethods :: [Method Resolved], - currentMethod :: Maybe (Method Resolved), - stackSize :: Word16, - locals :: Word16 } + generated :: [Instruction], -- ^ Already generated code (in current method) + currentPool :: Pool Resolved, -- ^ Already generated constants pool + doneMethods :: [Method Resolved], -- ^ Already generated class methods + currentMethod :: Maybe (Method Resolved), -- ^ Current method + stackSize :: Word16, -- ^ Maximum stack size for current method + locals :: Word16 -- ^ Maximum number of local variables for current method + } deriving (Eq,Show) +-- | Empty generator state +emptyGState :: GState emptyGState = GState { generated = [], currentPool = M.empty, @@ -30,14 +45,17 @@ emptyGState = GState { stackSize = 496, locals = 0 } +-- | Generate monad type Generate a = State GState a +-- | Append a constant to pool appendPool :: Constant Resolved -> Pool Resolved -> (Pool Resolved, Word16) appendPool c pool = let size = fromIntegral (M.size pool) pool' = M.insert size c pool in (pool', size) +-- | Add a constant to pool addItem :: Constant Resolved -> Generate Word16 addItem c = do pool <- St.gets currentPool @@ -49,6 +67,7 @@ addItem c = do St.put $ st {currentPool = pool'} return (i+1) +-- | Lookup in a pool lookupPool :: Constant Resolved -> Pool Resolved -> Maybe Word16 lookupPool c pool = fromIntegral `fmap` findIndex (== c) (M.elems pool) @@ -66,6 +85,7 @@ addSig c@(MethodSignature args ret) = do let bsig = encode c addItem (CUTF8 bsig) +-- | Add a constant into pool addToPool :: Constant Resolved -> Generate Word16 addToPool c@(CClass str) = do addItem (CUTF8 str) @@ -97,29 +117,35 @@ putInstruction instr = do let code = generated st St.put $ st {generated = code ++ [instr]} +-- | Generate one (zero-arguments) instruction i0 :: Instruction -> Generate () i0 = putInstruction +-- | Generate one one-argument instruction i1 :: (Word16 -> Instruction) -> Constant Resolved -> Generate () i1 fn c = do ix <- addToPool c i0 (fn ix) +-- | Generate one one-argument instruction i8 :: (Word8 -> Instruction) -> Constant Resolved -> Generate () i8 fn c = do ix <- addToPool c i0 (fn $ fromIntegral ix) +-- | Set maximum stack size for current method setStackSize :: Word16 -> Generate () setStackSize n = do st <- St.get St.put $ st {stackSize = n} +-- | Set maximum number of local variables for current method setMaxLocals :: Word16 -> Generate () setMaxLocals n = do st <- St.get St.put $ st {locals = n} +-- | Start generating new method startMethod :: [AccessFlag] -> B.ByteString -> MethodSignature -> Generate () startMethod flags name sig = do addToPool (CString name) @@ -136,6 +162,7 @@ startMethod flags name sig = do St.put $ st {generated = [], currentMethod = Just method } +-- | End of method generation endMethod :: Generate () endMethod = do m <- St.gets currentMethod @@ -150,7 +177,13 @@ endMethod = do currentMethod = Nothing, doneMethods = doneMethods st ++ [method']} -newMethod :: [AccessFlag] -> B.ByteString -> [ArgumentSignature] -> ReturnSignature -> Generate () -> Generate (NameType Method) +-- | Generate new method +newMethod :: [AccessFlag] -- ^ Access flags for method (public, static etc) + -> B.ByteString -- ^ Method name + -> [ArgumentSignature] -- ^ Signatures of method arguments + -> ReturnSignature -- ^ Method return signature + -> Generate () -- ^ Generator for method code + -> Generate (NameType Method) newMethod flags name args ret gen = do let sig = MethodSignature args ret startMethod flags name sig @@ -158,6 +191,7 @@ newMethod flags name args ret gen = do endMethod return (NameType name sig) +-- | Convert Generator state to method Code. genCode :: GState -> Code genCode st = Code { codeStackSize = stackSize st, @@ -171,12 +205,14 @@ genCode st = Code { where len = fromIntegral $ B.length $ encodeInstructions (generated st) +-- | Start class generation. initClass :: B.ByteString -> Generate Word16 initClass name = do addToPool (CClass "java/lang/Object") addToPool (CClass name) addToPool (CString "Code") +-- | Generate a class generate :: B.ByteString -> Generate () -> Class Resolved generate name gen = let generator = do diff --git a/JVM/Common.hs b/JVM/Common.hs index 7271e46..b3762c3 100644 --- a/JVM/Common.hs +++ b/JVM/Common.hs @@ -1,6 +1,12 @@ {-# LANGUAGE TypeFamilies, StandaloneDeriving, FlexibleInstances, FlexibleContexts, UndecidableInstances #-} --- | This module declares `high-level' data types for Java classes, methods etc. -module JVM.Common where +-- | This module declares some commonly used functions and instances. +module JVM.Common + (toCharList, + poolSize, + (!), + showListIx, + byteString + ) where import Codec.Binary.UTF8.String hiding (encode, decode) import Data.Binary diff --git a/JVM/Dump.hs b/JVM/Dump.hs index 3f450ed..a2c4c2e 100644 --- a/JVM/Dump.hs +++ b/JVM/Dump.hs @@ -11,6 +11,7 @@ import JVM.ClassFile import JVM.Converter import JVM.Assembler +-- | Dump a class to console. dumpClass :: Class Resolved -> IO () dumpClass cls = do putStr "Class: " diff --git a/Java/IO.hs b/Java/IO.hs index 7f13efb..9fd12f4 100644 --- a/Java/IO.hs +++ b/Java/IO.hs @@ -1,4 +1,5 @@ {-# LANGUAGE OverloadedStrings #-} +-- | This module exports definitions for some most used classes and methods from standard Java java.io package. module Java.IO where import Data.String @@ -8,9 +9,12 @@ import JVM.ClassFile import qualified Java.Lang +-- | java.io.PrintStream class name printStream :: IsString s => s printStream = "java/io/PrintStream" +-- | java.io.PrintStream class as field type +printStreamClass :: FieldType printStreamClass = ObjectType printStream println :: NameType Method diff --git a/Java/Lang.hs b/Java/Lang.hs index 74c40fc..9a929f1 100644 --- a/Java/Lang.hs +++ b/Java/Lang.hs @@ -1,4 +1,5 @@ {-# LANGUAGE OverloadedStrings #-} +-- | This module exports some definitions from standard Java java.lang package. module Java.Lang where import Data.String @@ -6,9 +7,16 @@ import Data.String import JVM.Common () -- import instances only import JVM.ClassFile +objectClass :: FieldType objectClass = ObjectType object + +stringClass :: FieldType stringClass = ObjectType string + +integerClass :: FieldType integerClass = ObjectType integer + +systemClass :: FieldType systemClass = ObjectType system object :: IsString s => s @@ -23,9 +31,11 @@ integer = "java/lang/Integer" system :: IsString s => s system = "java/lang/System" +-- | java.lang.Object.() method objectInit :: NameType Method objectInit = NameType "" $ MethodSignature [] ReturnsVoid +-- | java.lang.Integer.valueOf() method valueOfInteger :: NameType Method valueOfInteger = NameType "valueOf" $ MethodSignature [IntType] (Returns Java.Lang.integerClass) -- 2.25.1