diff --git a/JVM/Assembler.hs b/JVM/Assembler.hs
--- a/JVM/Assembler.hs
+++ b/JVM/Assembler.hs
@@ -10,6 +10,8 @@
    Code (..),
    IMM (..),
    CMP (..),
+   atype2byte,
+   encodeInstructions,
    encodeMethod,
    decodeMethod
   )
@@ -17,10 +19,10 @@
 
 import Control.Monad
 import Control.Applicative
+import Data.Ix (inRange)
 import Data.Word
 import qualified Data.Binary as Binary
 import qualified Data.ByteString.Lazy as B
-import Data.Array
 
 import Data.BinaryState
 import JVM.ClassFile
@@ -52,7 +54,7 @@
     codeExceptionsN :: Word16,
     codeExceptions :: [CodeException],
     codeAttrsN :: Word16,
-    codeAttributes :: [AttributeInfo] }
+    codeAttributes :: Attributes Pointers }
   deriving (Eq, Show)
 
 -- | Exception descriptor
@@ -72,7 +74,7 @@
 
   get = CodeException <$> get <*> get <*> get <*> get
 
-instance BinaryState Integer AttributeInfo where
+instance BinaryState Integer Attribute where
   put a = do
     let sz = 6 + attributeLength a      -- full size of AttributeInfo structure
     liftOffset (fromIntegral sz) Binary.put a
@@ -88,7 +90,7 @@
     put codeExceptionsN
     forM_ codeExceptions put
     put codeAttrsN
-    forM_ codeAttributes put
+    forM_ (attributesList codeAttributes) put
 
   get = do
     stackSz <- get
@@ -101,7 +103,7 @@
     excs <- replicateM (fromIntegral excn) get
     nAttrs <- get
     attrs <- replicateM (fromIntegral nAttrs) get
-    return $ Code stackSz locals len code excn excs nAttrs attrs
+    return $ Code stackSz locals len code excn excs nAttrs (AP attrs)
 
 -- | Read sequence of instructions (to end of stream)
 readInstructions :: GetState Integer [Instruction]
@@ -705,6 +707,11 @@
         | inRange (153, 158) c -> return $ IF (toEnum $ fromIntegral $ c-153)
         | inRange (159, 164) c -> IF_ICMP (toEnum $ fromIntegral $ c-159) <$> get
         | otherwise -> fail $ "Unknown instruction byte code: " ++ show c
+
+encodeInstructions :: [Instruction] -> B.ByteString
+encodeInstructions code =
+  let p list = forM_ list put
+  in  encodeWith p (0 :: Integer) code
   
 -- | Decode Java method
 decodeMethod :: B.ByteString -> Code
diff --git a/JVM/Builder.hs b/JVM/Builder.hs
new file mode 100644
--- /dev/null
+++ b/JVM/Builder.hs
@@ -0,0 +1,18 @@
+
+module JVM.Builder
+  (module JVM.Builder.Monad,
+   module JVM.Builder.Instructions,
+   arrayOf, sizedArray
+  ) where
+
+import JVM.ClassFile
+
+import JVM.Builder.Monad
+import JVM.Builder.Instructions
+
+arrayOf :: FieldType -> FieldType
+arrayOf t = Array Nothing t
+
+sizedArray :: Int -> FieldType -> FieldType
+sizedArray n t = Array (Just n) t
+
diff --git a/JVM/Builder/Instructions.hs b/JVM/Builder/Instructions.hs
new file mode 100644
--- /dev/null
+++ b/JVM/Builder/Instructions.hs
@@ -0,0 +1,162 @@
+
+module JVM.Builder.Instructions where
+
+import JVM.ClassFile
+import JVM.Assembler
+import JVM.Builder.Monad
+
+nop = i0 NOP
+aconst_null = i0 ACONST_NULL
+iconst_m1 = i0 ICONST_M1
+iconst_0 = i0 ICONST_0
+iconst_1 = i0 ICONST_1
+iconst_2 = i0 ICONST_2
+iconst_3 = i0 ICONST_3
+iconst_4 = i0 ICONST_4
+iconst_5 = i0 ICONST_5
+lconst_0 = i0 LCONST_0
+lconst_1 = i0 LCONST_1
+fconst_0 = i0 FCONST_0
+fconst_1 = i0 FCONST_1
+fconst_2 = i0 FCONST_2
+dconst_0 = i0 DCONST_0
+dconst_1 = i0 DCONST_1
+
+bipush x = i0 (BIPUSH x)
+sipush x = i0 (SIPUSH x)
+ldc1 x = i8 LDC1 x
+ldc2 x = i1 LDC2 x
+ldc2w x = i1 LDC2W x
+iload x = i8 ILOAD x
+lload x = i8 LLOAD x
+fload x = i8 FLOAD x
+dload x = i8 DLOAD x
+aload x = i8 ALOAD x
+
+iload_ x = i0 (ILOAD_ x)
+lload_ x = i0 (LLOAD_ x)
+fload_ x = i0 (FLOAD_ x)
+dload_ x = i0 (DLOAD_ x)
+aload_ x = i0 (ALOAD_ x)
+
+iaload = i0 IALOAD
+laload = i0 LALOAD
+faload = i0 FALOAD
+daload = i0 DALOAD
+aaload = i0 AALOAD
+caload = i0 CALOAD
+saload = i0 SALOAD
+
+istore x = i8 ISTORE x
+lstore x = i8 LSTORE x
+fstore x = i8 FSTORE x
+dstore x = i8 DSTORE x
+astore x = i8 ASTORE x
+
+istore_ x = i0 (ISTORE x)
+lstore_ x = i0 (LSTORE x)
+fstore_ x = i0 (FSTORE x)
+dstore_ x = i0 (DSTORE x)
+astore_ x = i0 (ASTORE x)
+
+iastore = i0 IASTORE
+lastore = i0 LASTORE
+fastore = i0 FASTORE
+dastore = i0 DASTORE
+aastore = i0 AASTORE
+bastore = i0 BASTORE
+castore = i0 CASTORE
+sastore = i0 SASTORE
+
+pop     = i0 POP    
+pop2    = i0 POP2   
+dup     = i0 DUP    
+dup_x1  = i0 DUP_X1 
+dup_x2  = i0 DUP_X2 
+dup2    = i0 DUP2   
+dup2_x1 = i0 DUP2_X1
+dup2_x2 = i0 DUP2_X2
+swap    = i0 SWAP   
+iadd    = i0 IADD   
+ladd    = i0 LADD   
+fadd    = i0 FADD   
+dadd    = i0 DADD   
+isub    = i0 ISUB   
+lsub    = i0 LSUB   
+fsub    = i0 FSUB   
+dsub    = i0 DSUB   
+imul    = i0 IMUL   
+lmul    = i0 LMUL   
+fmul    = i0 FMUL   
+dmul    = i0 DMUL   
+idiv    = i0 IDIV   
+ldiv    = i0 LDIV   
+fdiv    = i0 FDIV   
+ddiv    = i0 DDIV   
+irem    = i0 IREM   
+lrem    = i0 LREM   
+frem    = i0 FREM   
+drem    = i0 DREM   
+ineg    = i0 INEG   
+lneg    = i0 LNEG   
+fneg    = i0 FNEG   
+dneg    = i0 DNEG   
+ishl    = i0 ISHL   
+lshl    = i0 LSHL   
+ishr    = i0 ISHR   
+lshr    = i0 LSHR   
+iushr   = i0 IUSHR  
+lushr   = i0 LUSHR  
+iand    = i0 IAND   
+land    = i0 LAND   
+ior     = i0 IOR    
+lor     = i0 LOR    
+ixor    = i0 IXOR   
+lxor    = i0 LXOR   
+
+iinc x y = i0 (IINC x y)
+
+i2l  = i0 I2L 
+i2f  = i0 I2F 
+i2d  = i0 I2D 
+l2i  = i0 L2I 
+l2f  = i0 L2F 
+l2d  = i0 L2D 
+f2i  = i0 F2I 
+f2l  = i0 F2L 
+f2d  = i0 F2D 
+d2i  = i0 D2I 
+d2l  = i0 D2L 
+d2f  = i0 D2F 
+i2b  = i0 I2B 
+i2c  = i0 I2C 
+i2s  = i0 I2S 
+lcmp = i0 LCMP
+
+new cls =
+  i1 NEW (CClass cls)
+
+newArray t =
+  i0 (NEWARRAY $ atype2byte t)
+
+allocNewArray cls =
+  i1 ANEWARRAY (CClass cls)
+
+invokeVirtual cls sig =
+  i1 INVOKEVIRTUAL (CMethod cls sig)
+
+invokeStatic cls sig =
+  i1 INVOKESTATIC (CMethod cls sig)
+
+invokeSpecial cls sig =
+  i1 INVOKESPECIAL (CMethod cls sig)
+
+getStaticField cls sig =
+  i1 GETSTATIC (CField cls sig)
+
+loadString str =
+  i8 LDC1 (CString str)
+
+allocArray cls =
+  i1 ANEWARRAY (CClass cls)
+
diff --git a/JVM/Builder/Monad.hs b/JVM/Builder/Monad.hs
new file mode 100644
--- /dev/null
+++ b/JVM/Builder/Monad.hs
@@ -0,0 +1,188 @@
+{-# LANGUAGE FlexibleContexts, TypeFamilies, OverloadedStrings #-}
+module JVM.Builder.Monad where
+
+import Control.Monad.State as St
+import Data.Word
+import Data.List
+import Data.Binary
+import qualified Data.Map as M
+import qualified Data.Set as S
+import qualified Data.ByteString.Lazy as B
+
+import JVM.Common ()  -- import instances only
+import JVM.ClassFile
+import JVM.Assembler
+
+data GState = GState {
+  generated :: [Instruction],
+  currentPool :: Pool Resolved,
+  doneMethods :: [Method Resolved],
+  currentMethod :: Maybe (Method Resolved)}
+  deriving (Eq,Show)
+
+emptyGState = GState {
+  generated = [],
+  currentPool = M.empty,
+  doneMethods = [],
+  currentMethod = Nothing }
+
+type Generate a = State GState a
+
+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)
+
+addItem :: Constant Resolved -> Generate Word16
+addItem c = do
+  pool <- St.gets currentPool
+  case lookupPool c pool of
+    Just i -> return (i+1)
+    Nothing -> do
+      let (pool', i) = appendPool c pool
+      st <- St.get
+      St.put $ st {currentPool = pool'}
+      return (i+1)
+
+lookupPool :: Constant Resolved -> Pool Resolved -> Maybe Word16
+lookupPool c pool =
+  fromIntegral `fmap` findIndex (== c) (M.elems pool)
+
+addNT :: Binary (Signature a) => NameType a -> Generate Word16
+addNT (NameType name sig) = do
+  let bsig = encode sig
+  x <- addItem (CNameType name bsig)
+  addItem (CUTF8 name)
+  addItem (CUTF8 bsig)
+  return x
+
+addSig :: MethodSignature -> Generate Word16
+addSig c@(MethodSignature args ret) = do
+  let bsig = encode c
+  addItem (CUTF8 bsig)
+
+addToPool :: Constant Resolved -> Generate Word16
+addToPool c@(CClass str) = do
+  addItem (CUTF8 str)
+  addItem c
+addToPool c@(CField cls name) = do
+  addToPool (CClass cls)
+  addNT name
+  addItem c
+addToPool c@(CMethod cls name) = do
+  addToPool (CClass cls)
+  addNT name
+  addItem c
+addToPool c@(CIfaceMethod cls name) = do
+  addToPool (CClass cls)
+  addNT name
+  addItem c
+addToPool c@(CString str) = do
+  addToPool (CUTF8 str)
+  addItem c
+addToPool c@(CNameType name sig) = do
+  addItem (CUTF8 name)
+  addItem (CUTF8 sig)
+  addItem c
+addToPool c = addItem c
+
+putInstruction :: Instruction -> Generate ()
+putInstruction instr = do
+  st <- St.get
+  let code = generated st
+  St.put $ st {generated = code ++ [instr]}
+
+i0 :: Instruction -> Generate ()
+i0 = putInstruction
+
+i1 :: (Word16 -> Instruction) -> Constant Resolved -> Generate ()
+i1 fn c = do
+  ix <- addToPool c
+  i0 (fn ix)
+
+i8 :: (Word8 -> Instruction) -> Constant Resolved -> Generate ()
+i8 fn c = do
+  ix <- addToPool c
+  i0 (fn $ fromIntegral ix)
+
+startMethod :: [AccessFlag] -> B.ByteString -> MethodSignature -> Generate ()
+startMethod flags name sig = do
+  addToPool (CString name)
+  addSig sig
+  st <- St.get
+  let method = Method {
+    methodAccessFlags = S.fromList flags,
+    methodName = name,
+    methodSignature = sig,
+    methodAttributesCount = 0,
+    methodAttributes = AR M.empty }
+  St.put $ st {generated = [],
+               currentMethod = Just method }
+
+endMethod :: Generate ()
+endMethod = do
+  m <- St.gets currentMethod
+  code <- St.gets genCode
+  case m of
+    Nothing -> fail "endMethod without startMethod!"
+    Just method -> do
+      let method' = method {methodAttributes = AR $ M.fromList [("Code", encodeMethod code)],
+                            methodAttributesCount = 1}
+      st <- St.get
+      St.put $ st {generated = [],
+                   currentMethod = Nothing,
+                   doneMethods = doneMethods st ++ [method']}
+
+newMethod :: [AccessFlag] -> B.ByteString -> [ArgumentSignature] -> ReturnSignature -> Generate () -> Generate (NameType Method)
+newMethod flags name args ret gen = do
+  let sig = MethodSignature args ret
+  startMethod flags name sig
+  gen
+  endMethod
+  return (NameType name sig)
+
+genCode :: GState -> Code
+genCode st = Code {
+    codeStackSize = 4096,
+    codeMaxLocals = 100,
+    codeLength = len,
+    codeInstructions = generated st,
+    codeExceptionsN = 0,
+    codeExceptions = [],
+    codeAttrsN = 0,
+    codeAttributes = AP [] }
+  where
+    len = fromIntegral $ B.length $ encodeInstructions (generated st)
+
+initClass :: B.ByteString -> Generate Word16
+initClass name = do
+  addToPool (CClass "java/lang/Object")
+  addToPool (CClass name)
+  addToPool (CString "Code")
+
+generate :: B.ByteString -> Generate () -> Class Resolved
+generate name gen =
+  let generator = do
+        initClass name
+        gen
+      res = execState generator emptyGState
+      code = genCode res
+  in  Class {
+        magic = 0xCAFEBABE,
+        minorVersion = 0,
+        majorVersion = 50,
+        constsPoolSize = fromIntegral $ M.size (currentPool res),
+        constsPool = currentPool res,
+        accessFlags = S.fromList [ACC_PUBLIC, ACC_STATIC],
+        thisClass = name,
+        superClass = "java/lang/Object",
+        interfacesCount = 0,
+        interfaces = [],
+        classFieldsCount = 0,
+        classFields = [],
+        classMethodsCount = fromIntegral $ length (doneMethods res),
+        classMethods = doneMethods res,
+        classAttributesCount = 0,
+        classAttributes = AR M.empty }
+
diff --git a/JVM/ClassFile.hs b/JVM/ClassFile.hs
--- a/JVM/ClassFile.hs
+++ b/JVM/ClassFile.hs
@@ -1,15 +1,21 @@
-{-# LANGUAGE RecordWildCards, BangPatterns #-}
+{-# LANGUAGE RecordWildCards, BangPatterns, TypeFamilies, StandaloneDeriving, FlexibleContexts, FlexibleInstances, UndecidableInstances, TypeSynonymInstances #-}
 -- | This module declares (low-level) data types for Java .class files
 -- structures, and Binary instances to read/write them.
 module JVM.ClassFile
-  (ClassFile (..),
-   CpInfo (..),
-   FieldInfo (..),
-   MethodInfo (..),
-   AttributeInfo (..),
+  (Attribute (..),
    FieldType (..),
    FieldSignature, MethodSignature (..), ReturnSignature (..),
-   ArgumentSignature (..)
+   ArgumentSignature (..),
+   Pool, Link,
+   Method (..), Field (..), Class (..),
+   Constant (..),
+   Pointers, Resolved,
+   NameType (..),
+   HasSignature (..), HasAttributes (..),
+   AccessFlag (..), AccessFlags,
+   Attributes (..),
+   className,
+   apsize, arsize, arlist
   )
   where
 
@@ -21,7 +27,10 @@
 import Data.Binary.Put
 import Data.Char
 import Data.List
+import qualified Data.Set as S
+import qualified Data.Map as M
 import qualified Data.ByteString.Lazy as B
+import Codec.Binary.UTF8.String hiding (encode, decode)
 
 -- | Read one-byte Char
 getChar8 :: Get Char
@@ -29,34 +38,147 @@
   x <- getWord8
   return $ chr (fromIntegral x)
 
+toString :: B.ByteString -> String
+toString bstr = decodeString $ map (chr . fromIntegral) $ B.unpack bstr
+
+type family Link s a
+
+data Pointers = Pointers
+
+data Resolved = Resolved
+
+type instance Link Pointers a = Word16
+
+type instance Link Resolved a = a
+
+type family AccessFlags stage
+
+type instance AccessFlags Pointers = Word16
+
+type instance AccessFlags Resolved = S.Set AccessFlag
+
+data family Attributes stage
+
+data instance Attributes Pointers = AP {attributesList :: [Attribute]}
+  deriving (Eq, Show)
+data instance Attributes Resolved = AR (M.Map B.ByteString B.ByteString)
+  deriving (Eq, Show)
+
+arsize :: Attributes Resolved -> Int
+arsize (AR m) = M.size m
+
+arlist :: Attributes Resolved -> [(B.ByteString, B.ByteString)]
+arlist (AR m) = M.assocs m
+
+apsize :: Attributes Pointers -> Int
+apsize (AP list) = length list
+
+-- | Access flags. Used for classess, methods, variables.
+data AccessFlag =
+    ACC_PUBLIC 	     -- ^ 0x0001 Visible for all
+  | ACC_PRIVATE 	   -- ^ 0x0002 Visible only for defined class
+  | ACC_PROTECTED 	 -- ^ 0x0004 Visible only for subclasses
+  | ACC_STATIC 	     -- ^ 0x0008 Static method or variable
+  | ACC_FINAL 	     -- ^ 0x0010 No further subclassing or assignments
+  | ACC_SYNCHRONIZED -- ^ 0x0020 Uses monitors
+  | ACC_VOLATILE 	   -- ^ 0x0040 Could not be cached
+  | ACC_TRANSIENT 	 -- ^ 0x0080 
+  | ACC_NATIVE 	     -- ^ 0x0100 Implemented in other language
+  | ACC_INTERFACE 	 -- ^ 0x0200 Class is interface
+  | ACC_ABSTRACT 	   -- ^ 0x0400 
+  deriving (Eq, Show, Ord, Enum)
+
+class HasSignature a where
+  type Signature a
+
+instance HasSignature Field where
+  type Signature Field = FieldSignature
+
+instance HasSignature Method where
+  type Signature Method = MethodSignature
+
+-- | Name and signature pair. Used for methods and fields.
+data NameType a = NameType {
+  ntName :: B.ByteString,
+  ntSignature :: Signature a }
+
+instance Show (Signature a) => Show (NameType a) where
+  show (NameType n t) = toString n ++ ": " ++ show t
+
+deriving instance Eq (Signature a) => Eq (NameType a)
+
+instance (Binary (Signature a)) => Binary (NameType a) where
+  put (NameType n t) = putLazyByteString n >> put t
+
+  get = NameType <$> get <*> get
+
+-- | Constant pool item
+data Constant stage =
+    CClass (Link stage B.ByteString)
+  | CField {refClass :: Link stage B.ByteString, fieldNameType :: Link stage (NameType Field)}
+  | CMethod {refClass :: Link stage B.ByteString, nameType :: Link stage (NameType Method)}
+  | CIfaceMethod {refClass :: Link stage B.ByteString, nameType :: Link stage (NameType Method)}
+  | CString (Link stage B.ByteString)
+  | CInteger Word32
+  | CFloat Float
+  | CLong Integer
+  | CDouble Double
+  | CNameType (Link stage B.ByteString) (Link stage B.ByteString)
+  | CUTF8 {getString :: B.ByteString}
+  | CUnicode {getString :: B.ByteString}
+
+className ::  Constant Resolved -> B.ByteString
+className (CClass s) = s
+className x = error $ "Not a class: " ++ show x
+
+instance Show (Constant Resolved) where
+  show (CClass name) = "class " ++ toString name
+  show (CField cls nt) = "field " ++ toString cls ++ "." ++ show nt
+  show (CMethod cls nt) = "method " ++ toString cls ++ "." ++ show nt
+  show (CIfaceMethod cls nt) = "interface method " ++ toString cls ++ "." ++ show nt
+  show (CString s) = "String \"" ++ toString s ++ "\""
+  show (CInteger x) = show x
+  show (CFloat x) = show x
+  show (CLong x) = show x
+  show (CDouble x) = show x
+  show (CNameType name tp) = toString name ++ ": " ++ toString tp
+  show (CUTF8 s) = "UTF8 \"" ++ toString s ++ "\""
+  show (CUnicode s) = "Unicode \"" ++ toString s ++ "\""
+
+-- | Constant pool
+type Pool stage = M.Map Word16 (Constant stage)
+
 -- | Generic .class file format
-data ClassFile = ClassFile {
+data Class stage = Class {
   magic :: Word32,                   -- ^ Magic value: 0xCAFEBABE
   minorVersion :: Word16,
   majorVersion :: Word16,
   constsPoolSize :: Word16,          -- ^ Number of items in constants pool
-  constsPool :: [CpInfo],            -- ^ Constants pool itself
-  accessFlags :: Word16,             -- ^ See @JVM.Types.AccessFlag@
-  thisClass :: Word16,               -- ^ Constants pool item index for this class
-  superClass :: Word16,              -- ^ --/-- for super class, zero for java.lang.Object
+  constsPool :: Pool stage,            -- ^ Constants pool itself
+  accessFlags :: AccessFlags stage,             -- ^ See @JVM.Types.AccessFlag@
+  thisClass :: Link stage B.ByteString,               -- ^ Constants pool item index for this class
+  superClass :: Link stage B.ByteString,              -- ^ --/-- for super class, zero for java.lang.Object
   interfacesCount :: Word16,         -- ^ Number of implemented interfaces
-  interfaces :: [Word16],            -- ^ Constants pool item indexes for implemented interfaces
+  interfaces :: [Link stage B.ByteString],            -- ^ Constants pool item indexes for implemented interfaces
   classFieldsCount :: Word16,        -- ^ Number of class fileds
-  classFields :: [FieldInfo],        -- ^ Class fields
+  classFields :: [Field stage],        -- ^ Class fields
   classMethodsCount :: Word16,       -- ^ Number of class methods
-  classMethods :: [MethodInfo],      -- ^ Class methods
+  classMethods :: [Method stage],      -- ^ Class methods
   classAttributesCount :: Word16,    -- ^ Number of class attributes
-  classAttributes :: [AttributeInfo] -- ^ Class attributes
+  classAttributes :: Attributes stage -- ^ Class attributes
   }
-  deriving (Eq, Show)
 
-instance Binary ClassFile where
-  put (ClassFile {..}) = do
+deriving instance Eq (Constant Pointers)
+deriving instance Eq (Constant Resolved)
+deriving instance Show (Constant Pointers)
+
+instance Binary (Class Pointers) where
+  put (Class {..}) = do
     put magic
     put minorVersion
     put majorVersion
     put constsPoolSize
-    forM_ constsPool put
+    forM_ (M.elems constsPool) put
     put accessFlags
     put thisClass
     put superClass
@@ -67,7 +189,7 @@
     put classMethodsCount
     forM_ classMethods put
     put classAttributesCount
-    forM_ classAttributes put
+    forM_ (attributesList classAttributes) put
 
   get = do
     magic <- get
@@ -86,8 +208,10 @@
     classMethods <- replicateM (fromIntegral classMethodsCount) get
     asCount <- get
     as <- replicateM (fromIntegral $ asCount) get
-    return $ ClassFile magic minor major poolsize pool af this super
-               interfacesCount ifaces classFieldsCount classFields classMethodsCount classMethods asCount as
+    let pool' = M.fromList $ zip [1..] pool
+    return $ Class magic minor major poolsize pool' af this super
+               interfacesCount ifaces classFieldsCount classFields
+               classMethodsCount classMethods asCount (AP as)
 
 -- | Field signature format
 data FieldType =
@@ -252,35 +376,25 @@
               return (x: next)
     Nothing -> return []
 
--- | Constant pool item format
-data CpInfo =
-    CONSTANT_Class {nameIndex :: Word16}                                          -- ^ 7
-  | CONSTANT_Fieldref {classIndex :: Word16, nameAndTypeIndex :: Word16}	        -- ^ 9
-  | CONSTANT_Methodref 	{classIndex :: Word16, nameAndTypeIndex :: Word16}        -- ^ 10
-  | CONSTANT_InterfaceMethodref {classIndex :: Word16, nameAndTypeIndex :: Word16}-- ^ 11
-  | CONSTANT_String {stringIndex :: Word16}                                       -- ^ 8
-  | CONSTANT_Integer {fourBytes :: Word32}	                                      -- ^ 3
-  | CONSTANT_Float Float                                                          -- ^ 4
-  | CONSTANT_Long Word64                                                          -- ^ 5
-  | CONSTANT_Double Double                                                        -- ^ 6
-  | CONSTANT_NameAndType {nameIndex :: Word16, signatureIndex :: Word16} 	        -- ^ 12
-  | CONSTANT_Utf8 {stringLength :: Word16, stringBytes :: B.ByteString}   	      -- ^ 1
-  | CONSTANT_Unicode {stringLength :: Word16, stringBytes :: B.ByteString}   	    -- ^ 2
-  deriving (Eq, Show)
-
-instance Binary CpInfo where
-  put (CONSTANT_Class i) = putWord8 7 >> put i
-  put (CONSTANT_Fieldref i j) = putWord8 9 >> put i >> put j
-  put (CONSTANT_Methodref i j) = putWord8 10 >> put i >> put j
-  put (CONSTANT_InterfaceMethodref i j) = putWord8 11 >> put i >> put j
-  put (CONSTANT_String i) = putWord8 8 >> put i
-  put (CONSTANT_Integer x) = putWord8 3 >> put x
-  put (CONSTANT_Float x)   = putWord8 4 >> putFloat32be x
-  put (CONSTANT_Long x)    = putWord8 5 >> put x
-  put (CONSTANT_Double x)  = putWord8 6 >> putFloat64be x
-  put (CONSTANT_NameAndType i j) = putWord8 12 >> put i >> put j
-  put (CONSTANT_Utf8 l bs) = putWord8 1 >> put l >> putLazyByteString bs
-  put (CONSTANT_Unicode l bs) = putWord8 2 >> put l >> putLazyByteString bs
+instance Binary (Constant Pointers) where
+  put (CClass i) = putWord8 7 >> put i
+  put (CField i j) = putWord8 9 >> put i >> put j
+  put (CMethod i j) = putWord8 10 >> put i >> put j
+  put (CIfaceMethod i j) = putWord8 11 >> put i >> put j
+  put (CString i) = putWord8 8 >> put i
+  put (CInteger x) = putWord8 3 >> put x
+  put (CFloat x)   = putWord8 4 >> putFloat32be x
+  put (CLong x)    = putWord8 5 >> put x
+  put (CDouble x)  = putWord8 6 >> putFloat64be x
+  put (CNameType i j) = putWord8 12 >> put i >> put j
+  put (CUTF8 bs) = do
+                   putWord8 1
+                   put (fromIntegral (B.length bs) :: Word16)
+                   putLazyByteString bs
+  put (CUnicode bs) = do
+                   putWord8 2
+                   put (fromIntegral (B.length bs) :: Word16)
+                   putLazyByteString bs
 
   get = do
     !offset <- bytesRead
@@ -288,40 +402,44 @@
     case tag of
       1 -> do
         l <- get
-        bs <- getLazyByteString (fromIntegral l)
-        return $ CONSTANT_Utf8 l bs
+        bs <- getLazyByteString (fromIntegral (l :: Word16))
+        return $ CUTF8 bs
       2 -> do
         l <- get
-        bs <- getLazyByteString (fromIntegral l)
-        return $ CONSTANT_Unicode l bs
-      3  -> CONSTANT_Integer   <$> get
-      4  -> CONSTANT_Float     <$> getFloat32be
-      5  -> CONSTANT_Long      <$> get
-      6  -> CONSTANT_Double    <$> getFloat64be
-      7  -> CONSTANT_Class     <$> get
-      8  -> CONSTANT_String    <$> get
-      9  -> CONSTANT_Fieldref  <$> get <*> get
-      10 -> CONSTANT_Methodref <$> get <*> get
-      11 -> CONSTANT_InterfaceMethodref <$> get <*> get
-      12 -> CONSTANT_NameAndType <$> get <*> get
+        bs <- getLazyByteString (fromIntegral (l :: Word16))
+        return $ CUnicode bs
+      3  -> CInteger   <$> get
+      4  -> CFloat     <$> getFloat32be
+      5  -> CLong      <$> get
+      6  -> CDouble    <$> getFloat64be
+      7  -> CClass     <$> get
+      8  -> CString    <$> get
+      9  -> CField     <$> get <*> get
+      10 -> CMethod    <$> get <*> get
+      11 -> CIfaceMethod <$> get <*> get
+      12 -> CNameType    <$> get <*> get
       _  -> fail $ "Unknown constants pool entry tag: " ++ show tag
 
 -- | Class field format
-data FieldInfo = FieldInfo {
-  fieldAccessFlags :: Word16,
-  fieldNameIndex :: Word16,
-  fieldSignatureIndex :: Word16,
+data Field stage = Field {
+  fieldAccessFlags :: AccessFlags stage,
+  fieldName :: Link stage B.ByteString,
+  fieldSignature :: Link stage FieldSignature,
   fieldAttributesCount :: Word16,
-  fieldAttributes :: [AttributeInfo] }
-  deriving (Eq, Show)
+  fieldAttributes :: Attributes stage }
 
-instance Binary FieldInfo where
-  put (FieldInfo {..}) = do
+deriving instance Eq (Field Pointers)
+deriving instance Eq (Field Resolved)
+deriving instance Show (Field Pointers)
+deriving instance Show (Field Resolved)
+
+instance Binary (Field Pointers) where
+  put (Field {..}) = do
     put fieldAccessFlags 
-    put fieldNameIndex
-    put fieldSignatureIndex
+    put fieldName
+    put fieldSignature
     put fieldAttributesCount
-    forM_ fieldAttributes put
+    forM_ (attributesList fieldAttributes) put
 
   get = do
     af <- get
@@ -329,24 +447,28 @@
     si <- get
     n <- get
     as <- replicateM (fromIntegral n) get
-    return $ FieldInfo af ni si n as
+    return $ Field af ni si n (AP as)
 
 -- | Class method format
-data MethodInfo = MethodInfo {
-  methodAccessFlags :: Word16,
-  methodNameIndex :: Word16,
-  methodSignatureIndex :: Word16,
+data Method stage = Method {
+  methodAccessFlags :: AccessFlags stage,
+  methodName :: Link stage B.ByteString,
+  methodSignature :: Link stage MethodSignature,
   methodAttributesCount :: Word16,
-  methodAttributes :: [AttributeInfo] }
-  deriving (Eq, Show)
+  methodAttributes :: Attributes stage }
 
-instance Binary MethodInfo where
-  put (MethodInfo {..}) = do
+deriving instance Eq (Method Pointers)
+deriving instance Eq (Method Resolved)
+deriving instance Show (Method Pointers)
+deriving instance Show (Method Resolved)
+
+instance Binary (Method Pointers) where
+  put (Method {..}) = do
     put methodAccessFlags
-    put methodNameIndex 
-    put methodSignatureIndex
+    put methodName
+    put methodSignature
     put methodAttributesCount 
-    forM_ methodAttributes put
+    forM_ (attributesList methodAttributes) put
 
   get = do
     offset <- bytesRead
@@ -355,18 +477,23 @@
     si <- get
     n <- get
     as <- replicateM (fromIntegral n) get
-    return $ MethodInfo af ni si n as
+    return $ Method {
+               methodAccessFlags = af,
+               methodName = ni,
+               methodSignature = si,
+               methodAttributesCount = n,
+               methodAttributes = AP as }
 
 -- | Any (class/ field/ method/ ...) attribute format.
 -- Some formats specify special formats for @attributeValue@.
-data AttributeInfo = AttributeInfo {
+data Attribute = Attribute {
   attributeName :: Word16,
   attributeLength :: Word32,
   attributeValue :: B.ByteString }
   deriving (Eq, Show)
 
-instance Binary AttributeInfo where
-  put (AttributeInfo {..}) = do
+instance Binary Attribute where
+  put (Attribute {..}) = do
     put attributeName
     putWord32be attributeLength
     putLazyByteString attributeValue
@@ -376,5 +503,17 @@
     name <- get
     len <- getWord32be
     value <- getLazyByteString (fromIntegral len)
-    return $ AttributeInfo name len value
+    return $ Attribute name len value
+
+class HasAttributes a where
+  attributes :: a stage -> Attributes stage
+
+instance HasAttributes Class where
+  attributes = classAttributes
+
+instance HasAttributes Field where
+  attributes = fieldAttributes
+
+instance HasAttributes Method where
+  attributes = methodAttributes
 
diff --git a/JVM/Common.hs b/JVM/Common.hs
new file mode 100644
--- /dev/null
+++ b/JVM/Common.hs
@@ -0,0 +1,33 @@
+{-# LANGUAGE TypeFamilies, StandaloneDeriving, FlexibleInstances, FlexibleContexts, UndecidableInstances #-}
+-- | This module declares `high-level' data types for Java classes, methods etc.
+module JVM.Common where
+
+import Codec.Binary.UTF8.String hiding (encode, decode)
+import Data.Binary
+import Data.Binary.Put
+import qualified Data.ByteString.Lazy as B
+import Data.Char
+import Data.String
+import qualified Data.Map as M
+
+import JVM.ClassFile
+
+instance IsString B.ByteString where
+  fromString s = B.pack $ map (fromIntegral . ord) $ encodeString s
+
+toCharList :: B.ByteString -> [Int]
+toCharList bstr = map fromIntegral $ B.unpack bstr
+
+poolSize :: Pool stage -> Int
+poolSize = M.size
+
+(!) :: (Ord k) => M.Map k a -> k -> a
+(!) = (M.!)
+
+showListIx :: (Show a) => [a] -> String
+showListIx list = unlines $ zipWith s [1..] list
+  where s i x = show i ++ ":\t" ++ show x
+
+byteString ::  (Binary t) => t -> B.ByteString
+byteString x = runPut (put x)
+
diff --git a/JVM/Converter.hs b/JVM/Converter.hs
--- a/JVM/Converter.hs
+++ b/JVM/Converter.hs
@@ -17,168 +17,183 @@
 import Data.Bits
 import Data.Binary
 import qualified Data.ByteString.Lazy as B
-import Data.Array
 import qualified Data.Set as S
 import qualified Data.Map as M
 
 import JVM.ClassFile
-import JVM.Types
+import JVM.Common
 import JVM.Exceptions
 
 -- | Parse .class file data
-parseClass :: B.ByteString -> Class
+parseClass :: B.ByteString -> Class Resolved
 parseClass bstr = convertClass $ decode bstr
 
 -- | Parse class data from file
-parseClassFile :: FilePath -> IO Class
+parseClassFile :: FilePath -> IO (Class Resolved)
 parseClassFile path = convertClass `fmap` decodeFile path
 
-encodeClass :: Class -> B.ByteString
+encodeClass :: (Class Resolved) -> B.ByteString
 encodeClass cls = encode $ classFile cls
 
-convertClass :: ClassFile -> Class
-convertClass (ClassFile {..}) =
+convertClass :: Class Pointers -> Class Resolved
+convertClass (Class {..}) =
   let pool = constantPoolArray constsPool
       superName = className $ pool ! superClass
   in Class {
-      constantPool = pool,
-      classAccess = convertAccess accessFlags,
-      this = className $ pool ! thisClass,
-      super = if superClass == 0 then Nothing else Just superName,
-      implements = map (\i -> className $ pool ! i) interfaces,
-      fields = map (convertField pool) classFields,
-      methods = map (convertMethod pool) classMethods,
-      classAttrs = convertAttrs pool classAttributes }
+      magic = 0xCAFEBABE,
+      minorVersion = 0,
+      majorVersion = 50,
+      constsPoolSize = fromIntegral (M.size pool),
+      constsPool = pool,
+      accessFlags = convertAccess accessFlags,
+      thisClass = className $ pool ! thisClass,
+      superClass = if superClass == 0 then "" else superName,
+      interfacesCount = interfacesCount,
+      interfaces = map (\i -> className $ pool ! i) interfaces,
+      classFieldsCount = classFieldsCount,
+      classFields = map (convertField pool) classFields,
+      classMethodsCount = classMethodsCount,
+      classMethods = map (convertMethod pool) classMethods,
+      classAttributesCount = classAttributesCount,
+      classAttributes = convertAttrs pool classAttributes }
 
-classFile :: Class -> ClassFile
-classFile (Class {..}) = ClassFile {
+classFile :: Class Resolved -> Class Pointers
+classFile (Class {..}) = Class {
     magic = 0xCAFEBABE,
     minorVersion = 0,
     majorVersion = 50,
-    constsPoolSize = fromIntegral (length poolInfo + 1),
+    constsPoolSize = fromIntegral (M.size poolInfo + 1),
     constsPool = poolInfo,
-    accessFlags = access2word16 classAccess,
-    thisClass = force "this" $ poolClassIndex poolInfo this,
-    superClass = case super of
-                  Just s -> force "super" $ poolClassIndex poolInfo s
-                  Nothing -> 0,
-    interfacesCount = fromIntegral (length implements),
-    interfaces = map (force "ifaces" . poolIndex poolInfo) implements,
-    classFieldsCount = fromIntegral (length fields),
-    classFields = map (fieldInfo poolInfo) fields,
-    classMethodsCount = fromIntegral (length methods),
-    classMethods = map (methodInfo poolInfo) methods,
-    classAttributesCount = fromIntegral (M.size classAttrs),
-    classAttributes = map (attrInfo poolInfo) (M.assocs classAttrs) }
+    accessFlags = access2word16 accessFlags,
+    thisClass = force "this" $ poolClassIndex poolInfo thisClass,
+    superClass = force "super" $ poolClassIndex poolInfo superClass,
+    interfacesCount = fromIntegral (length interfaces),
+    interfaces = map (force "ifaces" . poolIndex poolInfo) interfaces,
+    classFieldsCount = fromIntegral (length classFields),
+    classFields = map (fieldInfo poolInfo) classFields,
+    classMethodsCount = fromIntegral (length classMethods),
+    classMethods = map (methodInfo poolInfo) classMethods,
+    classAttributesCount = fromIntegral $ arsize classAttributes,
+    classAttributes = to (arlist classAttributes) }
   where
-    poolInfo = toCPInfo constantPool
+    poolInfo = toCPInfo constsPool
+    to :: [(B.ByteString, B.ByteString)] -> Attributes Pointers
+    to pairs = AP (map (attrInfo poolInfo) pairs)
 
-toCPInfo :: Pool -> [CpInfo]
+toCPInfo :: Pool Resolved -> Pool Pointers
 toCPInfo pool = result
   where
-    result = map cpInfo $ elems pool
+    result = M.map cpInfo pool
 
-    cpInfo (CClass name) = CONSTANT_Class (force "class" $ poolIndex result name)
+    cpInfo :: Constant Resolved -> Constant Pointers
+    cpInfo (CClass name) = CClass (force "class" $ poolIndex result name)
     cpInfo (CField cls name) =
-      CONSTANT_Fieldref (force "field a" $ poolClassIndex result cls) (force "field b" $ poolNTIndex result name)
+      CField (force "field a" $ poolClassIndex result cls) (force "field b" $ poolNTIndex result name)
     cpInfo (CMethod cls name) =
-      CONSTANT_Methodref (force "method a" $ poolClassIndex result cls) (force ("method b: " ++ show name) $ poolNTIndex result name)
+      CMethod (force "method a" $ poolClassIndex result cls) (force ("method b: " ++ show name) $ poolNTIndex result name)
     cpInfo (CIfaceMethod cls name) =
-      CONSTANT_InterfaceMethodref (force "iface method a" $ poolIndex result cls) (force "iface method b" $ poolNTIndex result name)
-    cpInfo (CString s) = CONSTANT_String (force "string" $ poolIndex result s)
-    cpInfo (CInteger x) = CONSTANT_Integer x
-    cpInfo (CFloat x) = CONSTANT_Float x
-    cpInfo (CLong x) = CONSTANT_Long (fromIntegral x)
-    cpInfo (CDouble x) = CONSTANT_Double x
+      CIfaceMethod (force "iface method a" $ poolIndex result cls) (force "iface method b" $ poolNTIndex result name)
+    cpInfo (CString s) = CString (force "string" $ poolIndex result s)
+    cpInfo (CInteger x) = CInteger x
+    cpInfo (CFloat x) = CFloat x
+    cpInfo (CLong x) = CLong (fromIntegral x)
+    cpInfo (CDouble x) = CDouble x
     cpInfo (CNameType n t) =
-      CONSTANT_NameAndType (force "name" $ poolIndex result n) (force "type" $ poolIndex result t)
-    cpInfo (CUTF8 s) = CONSTANT_Utf8 (fromIntegral $ B.length s) s
-    cpInfo (CUnicode s) = CONSTANT_Unicode (fromIntegral $ B.length s) s
+      CNameType (force "name" $ poolIndex result n) (force "type" $ poolIndex result t)
+    cpInfo (CUTF8 s) = CUTF8 s
+    cpInfo (CUnicode s) = CUnicode s
 
 -- | Find index of given string in the list of constants
-poolIndex :: (Throws NoItemInPool e) => [CpInfo] -> B.ByteString -> EM e Word16
-poolIndex list name = case findIndex test list of
+poolIndex :: (Throws NoItemInPool e) => Pool Pointers -> B.ByteString -> EM e Word16
+poolIndex list name = case findIndex test (M.elems list) of
                         Nothing -> throw (NoItemInPool name)
                         Just i ->  return $ fromIntegral $ i+1
   where
-    test (CONSTANT_Utf8 _ s)    | s == name = True
-    test (CONSTANT_Unicode _ s) | s == name = True
+    test (CUTF8 s)    | s == name = True
+    test (CUnicode s) | s == name = True
     test _                                  = False
 
 -- | Find index of given string in the list of constants
-poolClassIndex :: (Throws NoItemInPool e) => [CpInfo] -> B.ByteString -> EM e Word16
-poolClassIndex list name = case findIndex checkString list of
+poolClassIndex :: (Throws NoItemInPool e) => Pool Pointers -> B.ByteString -> EM e Word16
+poolClassIndex list name = case findIndex checkString (M.elems list) of
                         Nothing -> throw (NoItemInPool name)
-                        Just i ->  case findIndex (checkClass $ fromIntegral $ i+1) list of
+                        Just i ->  case findIndex (checkClass $ fromIntegral $ i+1) (M.elems list) of
                                      Nothing -> throw (NoItemInPool $ i+1)
                                      Just j  -> return $ fromIntegral $ j+1
   where
-    checkString (CONSTANT_Utf8 _ s)    | s == name = True
-    checkString (CONSTANT_Unicode _ s) | s == name = True
+    checkString (CUTF8 s)    | s == name = True
+    checkString (CUnicode s) | s == name = True
     checkString _                                  = False
 
-    checkClass i (CONSTANT_Class x) | i == x = True
+    checkClass i (CClass x) | i == x = True
     checkClass _ _                           = False
 
 poolNTIndex list x@(NameType n t) = do
     ni <- poolIndex list n
     ti <- poolIndex list (byteString t)
-    case findIndex (check ni ti) list of
+    case findIndex (check ni ti) (M.elems list) of
       Nothing -> throw (NoItemInPool x)
       Just i  -> return $ fromIntegral (i+1)
   where
-    check ni ti (CONSTANT_NameAndType n' t')
+    check ni ti (CNameType n' t')
       | (ni == n') && (ti == t') = True
     check _ _ _                  = False
 
-fieldInfo :: [CpInfo] -> Field -> FieldInfo
-fieldInfo pool (Field {..}) = FieldInfo {
-  fieldAccessFlags = access2word16 fieldAccess,
-  fieldNameIndex = force "field name" $ poolIndex pool fieldName,
-  fieldSignatureIndex = force "signature" $ poolIndex pool (encode fieldSignature),
-  fieldAttributesCount = fromIntegral (M.size fieldAttrs),
-  fieldAttributes = map (attrInfo pool) (M.assocs fieldAttrs) }
+fieldInfo :: Pool Pointers -> Field Resolved -> Field Pointers
+fieldInfo pool (Field {..}) = Field {
+    fieldAccessFlags = access2word16 fieldAccessFlags,
+    fieldName = force "field name" $ poolIndex pool fieldName,
+    fieldSignature = force "signature" $ poolIndex pool (encode fieldSignature),
+    fieldAttributesCount = fromIntegral (arsize fieldAttributes),
+    fieldAttributes = to (arlist fieldAttributes) }
+  where
+    to :: [(B.ByteString, B.ByteString)] -> Attributes Pointers
+    to pairs = AP (map (attrInfo pool) pairs)
 
-methodInfo :: [CpInfo] -> Method -> MethodInfo
-methodInfo pool (Method {..}) = MethodInfo {
-  methodAccessFlags = access2word16 methodAccess,
-  methodNameIndex = force "method name" $ poolIndex pool methodName,
-  methodSignatureIndex = force "method sig" $ poolIndex pool (encode methodSignature),
-  methodAttributesCount = fromIntegral (M.size methodAttrs),
-  methodAttributes = map (attrInfo pool) (M.assocs methodAttrs) }
+methodInfo :: Pool Pointers -> Method Resolved -> Method Pointers
+methodInfo pool (Method {..}) = Method {
+    methodAccessFlags = access2word16 methodAccessFlags,
+    methodName = force "method name" $ poolIndex pool methodName,
+    methodSignature = force "method sig" $ poolIndex pool (encode methodSignature),
+    methodAttributesCount = fromIntegral (arsize methodAttributes),
+    methodAttributes = to (arlist methodAttributes) }
+  where
+    to :: [(B.ByteString, B.ByteString)] -> Attributes Pointers
+    to pairs = AP (map (attrInfo pool) pairs)
 
-attrInfo :: [CpInfo] -> (B.ByteString, B.ByteString) -> AttributeInfo
-attrInfo pool (name, value) = AttributeInfo {
+attrInfo :: Pool Pointers -> (B.ByteString, B.ByteString) -> Attribute
+attrInfo pool (name, value) = Attribute {
   attributeName = force "attr name" $ poolIndex pool name,
   attributeLength = fromIntegral (B.length value),
   attributeValue = value }
 
-constantPoolArray :: [CpInfo] -> Pool
-constantPoolArray list = pool
+constantPoolArray :: Pool Pointers -> Pool Resolved
+constantPoolArray ps = pool
   where
-    pool :: Pool
-    pool = listArray (1,n) $ map convert list
-    n = fromIntegral $ length list
+    pool :: Pool Resolved
+    pool = M.map convert ps
 
+    n = fromIntegral $ M.size ps
+
     convertNameType :: (HasSignature a, Binary (Signature a)) => Word16 -> NameType a
     convertNameType i =
       let (CNameType n s) = pool ! i
       in  NameType n (decode s)
 
-    convert (CONSTANT_Class i) = CClass $ getString $ pool ! i
-    convert (CONSTANT_Fieldref i j) = CField (className $ pool ! i) (convertNameType j)
-    convert (CONSTANT_Methodref i j) = CMethod (className $ pool ! i) (convertNameType j)
-    convert (CONSTANT_InterfaceMethodref i j) = CIfaceMethod (className $ pool ! i) (convertNameType j)
-    convert (CONSTANT_String i) = CString $ getString $ pool ! i
-    convert (CONSTANT_Integer x) = CInteger x
-    convert (CONSTANT_Float x)   = CFloat x
-    convert (CONSTANT_Long x)    = CLong (fromIntegral x)
-    convert (CONSTANT_Double x)  = CDouble x
-    convert (CONSTANT_NameAndType i j) = CNameType (getString $ pool ! i) (getString $ pool ! j)
-    convert (CONSTANT_Utf8 _ bs) = CUTF8 bs
-    convert (CONSTANT_Unicode _ bs) = CUnicode bs
+    convert (CClass i) = CClass $ getString $ pool ! i
+    convert (CField i j) = CField (className $ pool ! i) (convertNameType j)
+    convert (CMethod i j) = CMethod (className $ pool ! i) (convertNameType j)
+    convert (CIfaceMethod i j) = CIfaceMethod (className $ pool ! i) (convertNameType j)
+    convert (CString i) = CString $ getString $ pool ! i
+    convert (CInteger x) = CInteger x
+    convert (CFloat x)   = CFloat x
+    convert (CLong x)    = CLong (fromIntegral x)
+    convert (CDouble x)  = CDouble x
+    convert (CNameType i j) = CNameType (getString $ pool ! i) (getString $ pool ! j)
+    convert (CUTF8 bs) = CUTF8 bs
+    convert (CUnicode bs) = CUnicode bs
 
-convertAccess :: Word16 -> Access
+convertAccess :: AccessFlags Pointers -> AccessFlags Resolved
 convertAccess w = S.fromList $ concat $ zipWith (\i f -> if testBit w i then [f] else []) [0..] $ [
    ACC_PUBLIC,
    ACC_PRIVATE,
@@ -192,43 +207,48 @@
    ACC_INTERFACE,
    ACC_ABSTRACT ]
 
-access2word16 :: Access -> Word16
+access2word16 :: AccessFlags Resolved -> AccessFlags Pointers
 access2word16 fs = bitsOr $ map toBit $ S.toList fs
   where
     bitsOr = foldl (.|.) 0
     toBit f = 1 `shiftL` (fromIntegral $ fromEnum f)
 
-convertField :: Pool -> FieldInfo -> Field
-convertField pool (FieldInfo {..}) = Field {
-  fieldAccess = convertAccess fieldAccessFlags,
-  fieldName = getString $ pool ! fieldNameIndex,
-  fieldSignature = decode $ getString $ pool ! fieldSignatureIndex,
-  fieldAttrs = convertAttrs pool fieldAttributes }
+convertField :: Pool Resolved -> Field Pointers -> Field Resolved
+convertField pool (Field {..}) = Field {
+  fieldAccessFlags = convertAccess fieldAccessFlags,
+  fieldName = getString $ pool ! fieldName,
+  fieldSignature = decode $ getString $ pool ! fieldSignature,
+  fieldAttributesCount = fromIntegral (apsize fieldAttributes),
+  fieldAttributes = convertAttrs pool fieldAttributes }
 
-convertMethod :: Pool -> MethodInfo -> Method
-convertMethod pool (MethodInfo {..}) = Method {
-  methodAccess = convertAccess methodAccessFlags,
-  methodName = getString $ pool ! methodNameIndex,
-  methodSignature = decode $ getString $ pool ! methodSignatureIndex,
-  methodAttrs = convertAttrs pool methodAttributes }
+convertMethod :: Pool Resolved -> Method Pointers -> Method Resolved
+convertMethod pool (Method {..}) = Method {
+  methodAccessFlags = convertAccess methodAccessFlags,
+  methodName = getString $ pool ! methodName,
+  methodSignature = decode $ getString $ pool ! methodSignature,
+  methodAttributesCount = fromIntegral (apsize methodAttributes),
+  methodAttributes = convertAttrs pool methodAttributes }
 
-convertAttrs :: Pool -> [AttributeInfo] -> Attributes
-convertAttrs pool attrs = M.fromList $ map go attrs
+convertAttrs :: Pool Resolved -> Attributes Pointers -> Attributes Resolved
+convertAttrs pool (AP attrs) = AR (M.fromList $ map go attrs)
   where
-    go (AttributeInfo {..}) = (getString $ pool ! attributeName,
-                               attributeValue)
+    go :: Attribute -> (B.ByteString, B.ByteString)
+    go (Attribute {..}) = (getString $ pool ! attributeName,
+                           attributeValue)
 
 -- | Try to get class method by name
-methodByName :: Class -> B.ByteString -> Maybe Method
+methodByName :: Class Resolved -> B.ByteString -> Maybe (Method Resolved)
 methodByName cls name =
-  find (\m -> methodName m == name) (methods cls)
+  find (\m -> methodName m == name) (classMethods cls)
 
 -- | Try to get object attribute by name
-attrByName :: (HasAttributes a) => a -> B.ByteString -> Maybe B.ByteString
-attrByName x name = M.lookup name (attributes x)
+attrByName :: (HasAttributes a) => a Resolved -> B.ByteString -> Maybe B.ByteString
+attrByName x name =
+  let (AR m) = attributes x
+  in  M.lookup name m
 
 -- | Try to get Code for class method (no Code for interface methods)
-methodCode :: Class
+methodCode :: Class Resolved
            -> B.ByteString       -- ^ Method name
            -> Maybe B.ByteString
 methodCode cls name = do
diff --git a/JVM/Dump.hs b/JVM/Dump.hs
new file mode 100644
--- /dev/null
+++ b/JVM/Dump.hs
@@ -0,0 +1,32 @@
+{-# LANGUAGE OverloadedStrings #-}
+module JVM.Dump where
+
+import Control.Monad
+import qualified Data.Map as M
+import qualified Data.ByteString.Lazy as B
+import Text.Printf
+
+import JVM.Common ()
+import JVM.ClassFile
+import JVM.Converter
+import JVM.Assembler
+
+dumpClass :: Class Resolved -> IO ()
+dumpClass cls = do
+    putStr "Class: "
+    B.putStrLn (thisClass cls)
+    putStrLn "Constants pool:"
+    forM_ (M.assocs $ constsPool cls) $ \(i, c) ->
+      putStrLn $ printf "  #%d:\t%s" i (show c)
+    putStrLn "Methods:"
+    forM_ (classMethods cls) $ \m -> do
+      putStr ">> Method "
+      B.putStr (methodName m)
+      print (methodSignature m)
+      case attrByName m "Code" of
+        Nothing -> putStrLn "(no code)\n"
+        Just bytecode -> let code = decodeMethod bytecode
+                         in  forM_ (codeInstructions code) $ \i -> do
+                               putStr "  "
+                               print i
+
diff --git a/JVM/Exceptions.hs b/JVM/Exceptions.hs
new file mode 100644
--- /dev/null
+++ b/JVM/Exceptions.hs
@@ -0,0 +1,18 @@
+{-# LANGUAGE DeriveDataTypeable, ExistentialQuantification #-}
+module JVM.Exceptions where
+
+import Control.Monad.Exception
+
+data NoItemInPool = forall a. Show a => NoItemInPool a
+  deriving (Typeable)
+
+instance Exception NoItemInPool
+
+instance Show NoItemInPool where
+  show (NoItemInPool s) = "Internal error: no such item in pool: <" ++ show s ++ ">"
+
+force :: String -> EM AnyException a -> a
+force s x =
+  case tryEM x of
+    Right result -> result
+    Left  exc    -> error $ "Exception at " ++ s ++ ": " ++ show exc
diff --git a/JVM/Types.hs b/JVM/Types.hs
deleted file mode 100644
--- a/JVM/Types.hs
+++ /dev/null
@@ -1,162 +0,0 @@
-{-# LANGUAGE TypeFamilies, StandaloneDeriving, FlexibleInstances, FlexibleContexts, UndecidableInstances #-}
--- | This module declares `high-level' data types for Java classes, methods etc.
-module JVM.Types where
-
-import Codec.Binary.UTF8.String hiding (encode, decode)
-import Control.Applicative
-import Data.Array
-import Data.Binary
-import Data.Binary.Put
-import qualified Data.ByteString.Lazy as B
-import Data.Char
-import Data.String
-import qualified Data.Set as S
-import qualified Data.Map as M
-
-import JVM.ClassFile
-
-instance IsString B.ByteString where
-  fromString s = B.pack $ map (fromIntegral . ord) $ encodeString s
-
-toString :: B.ByteString -> String
-toString bstr = decodeString $ map (chr . fromIntegral) $ B.unpack bstr
-
--- | Constant pool
-type Pool = Array Word16 Constant
-
-asize :: (Ix i) => Array i e -> Int
-asize = length . elems
-
-showListIx :: (Show a) => [a] -> String
-showListIx list = unlines $ zipWith s [1..] list
-  where s i x = show i ++ ":\t" ++ show x
-
-class HasAttributes a where
-  attributes :: a -> Attributes
-
--- | Java class
-data Class = Class {
-  constantPool :: Pool,
-  classAccess :: Access,
-  this :: B.ByteString,        -- ^ this class name
-  super :: Maybe B.ByteString, -- ^ super class name
-  implements :: [B.ByteString], -- ^ implemented interfaces
-  fields :: [Field],
-  methods :: [Method],
-  classAttrs :: Attributes
-  }
-  deriving (Eq, Show)
-
-instance HasAttributes Class where
-  attributes = classAttrs
-
-class HasSignature a where
-  type Signature a
-
--- | Name and signature pair. Used for methods and fields.
-data NameType a = NameType {
-  ntName :: B.ByteString,
-  ntSignature :: Signature a }
-
-instance Show (Signature a) => Show (NameType a) where
-  show (NameType n t) = toString n ++ ": " ++ show t
-
-deriving instance Eq (Signature a) => Eq (NameType a)
-
--- | Constant pool item
-data Constant =
-    CClass B.ByteString
-  | CField {refClass :: B.ByteString, fieldNameType :: NameType Field}
-  | CMethod {refClass :: B.ByteString, nameType :: NameType Method}
-  | CIfaceMethod {refClass :: B.ByteString, nameType :: NameType Method}
-  | CString B.ByteString
-  | CInteger Word32
-  | CFloat Float
-  | CLong Integer
-  | CDouble Double
-  | CNameType B.ByteString B.ByteString
-  | CUTF8 {getString :: B.ByteString}
-  | CUnicode {getString :: B.ByteString}
-  deriving (Eq)
-
-className ::  Constant -> B.ByteString
-className (CClass s) = s
-className x = error $ "Not a class: " ++ show x
-
-instance Show Constant where
-  show (CClass name) = "class " ++ toString name
-  show (CField cls nt) = "field " ++ toString cls ++ "." ++ show nt
-  show (CMethod cls nt) = "method " ++ toString cls ++ "." ++ show nt
-  show (CIfaceMethod cls nt) = "interface method " ++ toString cls ++ "." ++ show nt
-  show (CString s) = "String \"" ++ toString s ++ "\""
-  show (CInteger x) = show x
-  show (CFloat x) = show x
-  show (CLong x) = show x
-  show (CDouble x) = show x
-  show (CNameType name tp) = toString name ++ ": " ++ toString tp
-  show (CUTF8 s) = "UTF8 \"" ++ toString s ++ "\""
-  show (CUnicode s) = "Unicode \"" ++ toString s ++ "\""
-
--- | Class field
-data Field = Field {
-  fieldAccess :: Access,
-  fieldName :: B.ByteString,
-  fieldSignature :: FieldSignature,
-  fieldAttrs :: Attributes }
-  deriving (Eq, Show)
-
-instance HasSignature Field where
-  type Signature Field = FieldSignature
-
-instance HasAttributes Field where
-  attributes = fieldAttrs
-
--- | Class method
-data Method = Method {
-  methodAccess :: Access,
-  methodName :: B.ByteString,
-  methodSignature :: MethodSignature,
-  methodAttrs :: Attributes }
-  deriving (Eq, Show)
-
-instance HasSignature Method where
-  type Signature Method = MethodSignature
-
-instance HasAttributes Method where
-  attributes = methodAttrs
-
--- | Set of access flags
-type Access = S.Set AccessFlag
-
--- | Access flags. Used for classess, methods, variables.
-data AccessFlag =
-    ACC_PUBLIC 	     -- ^ 0x0001 Visible for all
-  | ACC_PRIVATE 	   -- ^ 0x0002 Visible only for defined class
-  | ACC_PROTECTED 	 -- ^ 0x0004 Visible only for subclasses
-  | ACC_STATIC 	     -- ^ 0x0008 Static method or variable
-  | ACC_FINAL 	     -- ^ 0x0010 No further subclassing or assignments
-  | ACC_SYNCHRONIZED -- ^ 0x0020 Uses monitors
-  | ACC_VOLATILE 	   -- ^ 0x0040 Could not be cached
-  | ACC_TRANSIENT 	 -- ^ 0x0080 
-  | ACC_NATIVE 	     -- ^ 0x0100 Implemented in other language
-  | ACC_INTERFACE 	 -- ^ 0x0200 Class is interface
-  | ACC_ABSTRACT 	   -- ^ 0x0400 
-  deriving (Eq, Show, Ord, Enum)
-
--- | Generic attribute
-data Attribute = Attribute {
-  attrName :: B.ByteString,
-  attrValue :: B.ByteString }
-  deriving (Eq, Show)
-
--- | Set of attributes
-type Attributes = M.Map B.ByteString B.ByteString
-
-instance (Binary (Signature a)) => Binary (NameType a) where
-  put (NameType n t) = putLazyByteString n >> put t
-
-  get = NameType <$> get <*> get
-
-byteString ::  (Binary t) => t -> B.ByteString
-byteString x = runPut (put x)
-
diff --git a/Java/IO.hs b/Java/IO.hs
new file mode 100644
--- /dev/null
+++ b/Java/IO.hs
@@ -0,0 +1,26 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Java.IO where
+
+import Data.String
+
+import JVM.Common ()  -- import instances only
+import JVM.ClassFile
+
+import qualified Java.Lang
+
+printStream :: IsString s => s
+printStream = "java/io/PrintStream"
+
+printStreamClass = ObjectType printStream
+
+println :: NameType Method
+println = NameType "println" $ MethodSignature [Java.Lang.stringClass] ReturnsVoid
+
+out :: NameType Field
+out = NameType "out" printStreamClass
+
+printf :: NameType Method
+printf =
+  NameType "printf" $ MethodSignature [Java.Lang.stringClass,
+                                       Array Nothing Java.Lang.objectClass] (Returns printStreamClass)
+
diff --git a/Java/Lang.hs b/Java/Lang.hs
new file mode 100644
--- /dev/null
+++ b/Java/Lang.hs
@@ -0,0 +1,31 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Java.Lang where
+
+import Data.String
+
+import JVM.Common ()  -- import instances only
+import JVM.ClassFile
+
+objectClass = ObjectType object
+stringClass = ObjectType string
+integerClass = ObjectType integer
+systemClass = ObjectType system
+
+object :: IsString s => s
+object = "java/lang/Object"
+
+string :: IsString s => s
+string = "java/lang/String"
+
+integer :: IsString s => s
+integer = "java/lang/Integer"
+
+system :: IsString s => s
+system = "java/lang/System"
+
+objectInit :: NameType Method
+objectInit = NameType "<init>" $ MethodSignature [] ReturnsVoid
+
+valueOfInteger :: NameType Method
+valueOfInteger = NameType "valueOf" $ MethodSignature [IntType] (Returns Java.Lang.integerClass)
+
diff --git a/TestGen.hs b/TestGen.hs
new file mode 100644
--- /dev/null
+++ b/TestGen.hs
@@ -0,0 +1,49 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+import qualified Data.ByteString.Lazy as B
+
+import JVM.ClassFile
+import JVM.Converter
+import JVM.Assembler
+import JVM.Builder
+
+import qualified Java.Lang
+import qualified Java.IO
+
+test :: Generate ()
+test = do
+  newMethod [ACC_PUBLIC] "<init>" [] ReturnsVoid $ do
+      aload_ I0
+      invokeSpecial Java.Lang.object Java.Lang.objectInit
+      i0 RETURN
+
+  hello <- newMethod [ACC_PUBLIC, ACC_STATIC] "hello" [IntType] ReturnsVoid $ do
+      getStaticField Java.Lang.system Java.IO.out
+      loadString "Здравствуй, мир!"
+      invokeVirtual Java.IO.printStream Java.IO.println
+      getStaticField Java.Lang.system Java.IO.out
+      loadString "Argument: %d\n"
+      iconst_1
+      allocArray Java.Lang.object
+      dup
+      iconst_0
+      iload_ I0
+      invokeStatic Java.Lang.integer Java.Lang.valueOfInteger
+      aastore
+      invokeVirtual Java.IO.printStream Java.IO.printf
+      pop
+      i0 RETURN
+
+  newMethod [ACC_PUBLIC, ACC_STATIC] "main" [arrayOf Java.Lang.stringClass] ReturnsVoid $ do
+      iconst_5
+      invokeStatic "Test" hello
+      i0 RETURN
+
+  return ()
+
+testClass ::  Class Resolved
+testClass = generate "Test" test
+
+main = do
+  B.writeFile "Test.class" (encodeClass testClass)
+
diff --git a/dump-class.hs b/dump-class.hs
--- a/dump-class.hs
+++ b/dump-class.hs
@@ -1,37 +1,22 @@
 {-# LANGUAGE OverloadedStrings #-}
 module Main where
 
-import Control.Monad
-import Data.Array
+import Data.Binary
 import System.Environment
-import qualified Data.ByteString.Lazy as B
-import Text.Printf
+import qualified Data.Map as M
 
-import JVM.Types
+import JVM.Common
+import JVM.ClassFile
 import JVM.Converter
-import JVM.Assembler
+import JVM.Dump
 
 main = do
   args <- getArgs
   case args of
     [clspath] -> do
+      clsFile <- decodeFile clspath
+      putStrLn $ showListIx $ M.elems $ constsPool (clsFile :: Class Pointers)
       cls <- parseClassFile clspath
-      putStr "Class: "
-      B.putStrLn (this cls)
-      putStrLn "Constants pool:"
-      forM_ (assocs $ constantPool cls) $ \(i, c) ->
-        putStrLn $ printf "  #%d:\t%s" i (show c)
-      putStrLn "Methods:"
-      forM_ (methods cls) $ \m -> do
-        putStr ">> Method "
-        B.putStr (methodName m)
-        print (methodSignature m)
-        case attrByName m "Code" of
-          Nothing -> putStrLn "(no code)\n"
-          Just bytecode -> let code = decodeMethod bytecode
-                           in  forM_ (codeInstructions code) $ \i -> do
-                                 putStr "  "
-                                 print i
-
+      dumpClass cls
     _ -> error "Synopsis: dump-class File.class"
 
diff --git a/hs-java.cabal b/hs-java.cabal
--- a/hs-java.cabal
+++ b/hs-java.cabal
@@ -1,5 +1,5 @@
 Name:           hs-java
-Version:        0.1
+Version:        0.2
 Cabal-Version:  >= 1.6
 License:        BSD3
 License-File:   LICENSE
@@ -9,21 +9,33 @@
 Category:       Jvm
 Build-Type:     Simple
 Description:    This package declares data types for Java .class files format and functions
-                to assemble/disassemble Java bytecode.
+                to assemble/disassemble Java bytecode. See dump-class.hs, rebuild-class.hs,
+                TestGen.hs for examples of usage.
 
 Extra-source-files: dump-class.hs
+                    rebuild-class.hs
+                    TestGen.hs
 
 library
-  Exposed-Modules: JVM.Types
+  Exposed-Modules: JVM.Common
                    JVM.ClassFile
                    JVM.Assembler
                    JVM.Converter
+                   JVM.Builder
+                   JVM.Builder.Monad
+                   JVM.Builder.Instructions
+                   JVM.Dump
+                   JVM.Exceptions
+                   Java.Lang
+                   Java.IO
 
-  Build-Depends:  base >= 3 && <= 5, haskell98, containers, binary,
+  Build-Depends:  base >= 3 && <= 5, containers, binary,
                   mtl, directory, filepath, utf8-string, array,
                   bytestring, data-binary-ieee754, binary-state,
                   control-monad-exception
 
   ghc-options: -fwarn-unused-imports
 
-
+Source-repository head
+  type:     git
+  location: git remote add origin git@gitorious.org:hs-java/hs-java.git
diff --git a/rebuild-class.hs b/rebuild-class.hs
new file mode 100644
--- /dev/null
+++ b/rebuild-class.hs
@@ -0,0 +1,25 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+import Data.Binary
+import System.Environment
+import qualified Data.ByteString.Lazy as B
+import qualified Data.Map as M
+
+import JVM.Common
+import JVM.ClassFile
+import JVM.Converter
+import JVM.Dump
+
+main = do
+  args <- getArgs
+  case args of
+    [clspath,outpath] -> do
+      cls <- parseClassFile clspath
+      clsfile <- decodeFile clspath :: IO (Class Pointers)
+      dumpClass cls
+      putStrLn $ "Source pool:\n" ++ showListIx (M.elems $ constsPool clsfile)
+      let result = classFile cls
+      putStrLn $ "Result pool:\n" ++ showListIx (M.elems $ constsPool result)
+      B.writeFile outpath (encodeClass cls)
+
+    _ -> error "Synopsis: rebuild-class File.class Output.class"
