Skip to content

Commit e8c3180

Browse files
committed
Fix a bug in constant pool handling (grr), add double/float support, start laying the groundwork for parsing the bytecode
1 parent bebb108 commit e8c3180

File tree

4 files changed

+191
-43
lines changed

4 files changed

+191
-43
lines changed

src/Data/Prickler.hs

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,13 @@ import Data.Monoid hiding (Sum, Product, All)
1616
import Data.Binary.Get hiding (Done, Partial, skip)
1717
import qualified Data.Binary.Get as Get
1818
import Data.Binary.Builder
19+
import Data.Binary.IEEE754
1920
import qualified Data.Map as M
2021
import Data.ByteString.Base16
2122
import qualified Data.ByteString.Lazy as BL
2223
import qualified Data.Vector.Generic as G
2324
import Control.Monad
25+
import Debug.Trace
2426

2527
import Data.Int
2628
import Data.Word
@@ -107,7 +109,7 @@ data State a = State { written :: {-# UNPACK #-} !Int64, builder :: !Builder, co
107109
instance Functor State where
108110
fmap f (State w b v) = State w b (f v)
109111

110-
newtype PutM a = PutM { runPut :: Int64 -> State a }
112+
newtype PutM a = PutM { runPutM :: Int64 -> State a }
111113

112114
instance Functor PutM where
113115
fmap f (PutM g) = PutM (fmap f . g)
@@ -170,7 +172,7 @@ tagged (Prickler gi pi) elim sum = Prickler getter (merged (mapAll (adjust pi) s
170172
Just (Exists (Partial maker _ _)) -> maker
171173

172174

173-
taggedSized :: (Show i, Ord i, Integral s) => Prickler i -> Prickler s -> (forall r. a -> EliminatorWrapper ts r) -> All (Indexed i (Partial Put Get a)) ts -> Prickler a
175+
taggedSized :: (Ord i, Integral s) => Prickler i -> Prickler s -> (forall r. a -> EliminatorWrapper ts r) -> All (Indexed i (Partial Put Get a)) ts -> Prickler a
174176
taggedSized (Prickler gi pi) (Prickler gs ps) elim sum = Prickler getter (merged (mapAll (adjust pi) sum) . elim)
175177
where
176178
merged :: All ((:<-@) r) ts -> EliminatorWrapper ts r -> r
@@ -186,7 +188,7 @@ taggedSized (Prickler gi pi) (Prickler gs ps) elim sum = Prickler getter (merged
186188
tag <- gi
187189
size <- gs
188190
case M.lookup tag ps of
189-
Nothing -> fail $ "Invalid tag! " ++ show tag
191+
Nothing -> fail $ "Invalid tag!"
190192
Just (Exists (Partial maker _ _)) -> do
191193
bs <- getLazyByteString (fromIntegral size)
192194
return $ runGet maker bs
@@ -243,10 +245,10 @@ int64be = wrap fromIntegral fromIntegral word64be
243245
int64le = wrap fromIntegral fromIntegral word64le
244246

245247
float :: Prickler Float
246-
float = error "foo"
248+
float = Prickler getFloat32be (const (error "not yet implemented"))
247249

248250
double :: Prickler Double
249-
double = error "bar"
251+
double = Prickler getFloat64be (const (error "not yet implemented"))
250252

251253
delimited :: Integral i => Prickler i -> Prickler a -> Prickler a
252254
delimited (Prickler gi pi) (Prickler ga pa) = Prickler getter putter
@@ -256,21 +258,24 @@ delimited (Prickler gi pi) (Prickler ga pa) = Prickler getter putter
256258
bs <- getLazyByteString (fromIntegral len)
257259
return $ runGet ga bs
258260

259-
putter xs = undefined
261+
putter xs = let bs = toLazyByteString (builder $ runPutM (pa xs) 0) in
262+
pi (fromIntegral $ BL.length bs) <> PutM (\w -> State (w + (fromIntegral $ BL.length bs)) (fromLazyByteString bs) ())
263+
260264

261265
all :: G.Vector v a => Prickler a -> Prickler (v a)
262-
all = undefined
266+
all (Prickler ga pa) = Prickler getter putter
267+
where
268+
getter = undefined
269+
putter = undefined
263270

264271
byteString :: Integral i => Prickler i -> Prickler BL.ByteString
265-
byteString (Prickler gi pi) = Prickler getter putter
266-
where
267-
getter = do len <- gi; getLazyByteString (fromIntegral len)
268-
putter xs = let len = BL.length xs in pi (fromIntegral len) <> PutM (\w -> State (w + fromIntegral len) (fromLazyByteString xs) ())
272+
byteString pi = delimited pi remainingByteString
269273

270274
remainingByteString :: Prickler BL.ByteString
271275
remainingByteString = Prickler getRemainingLazyByteString putter
272276
where
273-
putter xs = undefined
277+
putter xs = PutM (\w -> State (w + (fromIntegral $ BL.length xs)) (fromLazyByteString xs) ())
278+
274279

275280
gvector :: (Integral i, G.Vector v a) => Prickler i -> Prickler a -> Prickler (v a)
276281
gvector (Prickler gi pi) (Prickler ga pa) = Prickler getter putter

src/Java/ClassFormat/Encoding.hs

Lines changed: 49 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ import Control.Monad
1414
import qualified Data.ByteString.Lazy as BL
1515
import Control.Lens hiding ((#), Indexed)
1616
import qualified Data.Map as M
17+
import qualified Data.IntMap as IM
18+
import Debug.Trace
1719

1820
import Java.ClassFormat.Raw hiding (constantPool, interfaces, fields, methods, attributes)
1921
import Java.Bytecode.Raw
@@ -44,39 +46,42 @@ innerClass = untagged elim_InnerClass . alt InnerClass $ con2 :> con2 :
4446
localVariable = untagged elim_LocalVariable . alt LocalVariable $ word16be :> word16be :> con2 :>con2 :> word16be :> Nil
4547

4648

47-
attribute cpool = taggedSized con2 word32be (EliminatorWrapper . elim_Attribute)
48-
$ attr "ConstantValue" #? alt ConstantValue (con2 :> Nil)
49-
:> attr "Code" #? alt Code (codeAttribute (attribute cpool) :> Nil) -- fix?
50-
:> attr "StackMapTable" #? alt StackMapTable Nil
51-
:> attr "Exceptions" #? alt Exceptions (gvector word16be con2 :> Nil)
52-
:> attr "InnerClasses" #? alt InnerClasses (gvector word16be innerClass :> Nil)
53-
:> attr "EnclosingMethod" #? alt EnclosingMethod (con2 :> con2 :> Nil)
54-
:> attr "Synthetic" #? alt Synthetic Nil
55-
:> attr "Signature" #? alt Signature (con2 :> Nil)
56-
:> attr "SourceFile" #? alt SourceFile (con2 :> Nil)
57-
:> attr "SourceDebugExtension" #? alt SourceDebugExtension (remainingByteString :> Nil)
58-
:> attr "LineNumberTable" #? alt LineNumberTable (gvector word16be (pair word16be word16be) :> Nil)
59-
:> attr "LocalVariableTable" #? alt LocalVariableTable (gvector word16be localVariable :> Nil)
60-
:> attr "LocalVariableTypeTable" #? alt LocalVariableTypeTable (gvector word16be localVariable :> Nil)
61-
:> attr "Deprecated" #? alt Deprecated Nil
62-
:> attr "RuntimeVisibleAnnotations" #? alt RuntimeVisibleAnnotations (gvector word16be annotation :> Nil)
63-
:> attr "RuntimeInvisibleAnnotations" #? alt RuntimeInvisibleAnnotations (gvector word16be annotation :> Nil)
64-
:> attr "RuntimeVisibleParameterAnnotations" #? alt RuntimeVisibleParameterAnnotations (gvector word8 (gvector word16be annotation) :> Nil)
65-
:> attr "RuntimeInvisibleParameterAnnotations" #? alt RuntimeInvisibleParameterAnnotations (gvector word8 (gvector word16be annotation) :> Nil)
66-
:> attr "AnnotationDefault" #? alt AnnotationDefault (value :> Nil)
67-
:> attr "BootstrapMethods" #? alt BootstrapMethods Nil
68-
:> attr "Scala" #? alt Custom (remainingByteString :> Nil) -- TODO: add catchall
69-
:> Nil
49+
attribute :: IM.IntMap Constant -> Prickler Attribute
50+
attribute cpool = inner
7051
where
52+
inner = taggedSized con2 word32be (EliminatorWrapper . elim_Attribute)
53+
$ attr "ConstantValue" #? alt ConstantValue (con2 :> Nil)
54+
:> attr "Code" #? alt Code (codeAttribute inner :> Nil)
55+
:> attr "StackMapTable" #? alt StackMapTable Nil
56+
:> attr "Exceptions" #? alt Exceptions (gvector word16be con2 :> Nil)
57+
:> attr "InnerClasses" #? alt InnerClasses (gvector word16be innerClass :> Nil)
58+
:> attr "EnclosingMethod" #? alt EnclosingMethod (con2 :> con2 :> Nil)
59+
:> attr "Synthetic" #? alt Synthetic Nil
60+
:> attr "Signature" #? alt Signature (con2 :> Nil)
61+
:> attr "SourceFile" #? alt SourceFile (con2 :> Nil)
62+
:> attr "SourceDebugExtension" #? alt SourceDebugExtension (remainingByteString :> Nil)
63+
:> attr "LineNumberTable" #? alt LineNumberTable (gvector word16be (pair word16be word16be) :> Nil)
64+
:> attr "LocalVariableTable" #? alt LocalVariableTable (gvector word16be localVariable :> Nil)
65+
:> attr "LocalVariableTypeTable" #? alt LocalVariableTypeTable (gvector word16be localVariable :> Nil)
66+
:> attr "Deprecated" #? alt Deprecated Nil
67+
:> attr "RuntimeVisibleAnnotations" #? alt RuntimeVisibleAnnotations (gvector word16be annotation :> Nil)
68+
:> attr "RuntimeInvisibleAnnotations" #? alt RuntimeInvisibleAnnotations (gvector word16be annotation :> Nil)
69+
:> attr "RuntimeVisibleParameterAnnotations" #? alt RuntimeVisibleParameterAnnotations (gvector word8 (gvector word16be annotation) :> Nil)
70+
:> attr "RuntimeInvisibleParameterAnnotations" #? alt RuntimeInvisibleParameterAnnotations (gvector word8 (gvector word16be annotation) :> Nil)
71+
:> attr "AnnotationDefault" #? alt AnnotationDefault (value :> Nil)
72+
:> attr "BootstrapMethods" #? alt BootstrapMethods Nil
73+
:> attr "Scala" #? alt Custom (remainingByteString :> Nil) -- TODO: add catchall
74+
:> Nil
75+
7176
(#?) :: Maybe Con2 -> Partial Put Get Attribute ts -> Indexed Con2 (Partial Put Get Attribute) ts
7277
Nothing #? a = Con2 0 # Partial (fail "failed") (error "failed") (error "failed")
7378
Just c #? a = c # a
7479

7580
attr :: BL.ByteString -> Maybe Con2
76-
attr = fmap Con2 . flip M.lookup tagMap
81+
attr = traceShow tagMap $ fmap Con2 . flip M.lookup tagMap
7782

7883
tagMap :: M.Map BL.ByteString Word16
79-
tagMap = M.fromList . mapMaybe (_1 (^? _Utf8) $) . flip zip [1..] . V.toList $ cpool
84+
tagMap = M.fromList . map (fmap fromIntegral . swap) . mapMaybe (_2 (^? _Utf8) $) . IM.toList $ cpool
8085

8186
-- attribute = undefined
8287

@@ -113,19 +118,33 @@ constant = tagged word8 (EliminatorWrapper . elim_Constant)
113118
:> 18 # alt InvokeDynamic (word16be :> con2 :> Nil)
114119
:> Nil
115120

116-
constantPool :: Prickler (V.Vector Constant)
121+
constantPool :: Prickler (IM.IntMap Constant)
117122
constantPool = Prickler getter putter
118123
where
119-
getter = do len <- getWord16be; V.replicateM (fromIntegral len- 1) (get constant)
120-
putter xs = put word16be (fromIntegral (V.length xs)) <> V.mapM_ (put constant) xs
124+
listGetter :: Int -> Int -> Get [(Int, Constant)]
125+
listGetter 0 off = pure []
126+
listGetter n off = do
127+
x <- get constant
128+
let delta = size x
129+
xs <- listGetter (n - delta) (off + delta)
130+
return ((off, x) : xs)
131+
132+
getter = do len <- getWord16be; IM.fromList <$> listGetter (fromIntegral len - 1) 1
133+
putter xs = put word16be (fromIntegral . sum $ map (size . snd) flat) <> mapM_ (put constant . snd) flat
134+
where flat = IM.toAscList xs
135+
136+
size :: Constant -> Int
137+
size (Long _) = 2
138+
size (Double _) = 2
139+
size _ = 1
121140

122141
basicClass :: Prickler Class
123142
basicClass = Prickler getter putter
124143
where
125144
getter = do
126145
maj <- get word16be
127146
min <- get word16be
128-
cons <- get constantPool -- this should really be completely synthetic...
147+
cons <- get constantPool -- this should really be at least partially synthetic...
129148
flags <- get word16be
130149
cname <- get con2
131150
sname <- get con2
@@ -147,7 +166,7 @@ klass :: Prickler Class
147166
klass = skip (expect 0xcafebabe word32be) basicClass
148167

149168
test = do
150-
x <- BL.readFile "/Users/copumpkin/Sandbox/Scala/tinker/target/scala-2.10/classes/tinker/optimized/Main$$anon$1.class"
169+
x <- BL.readFile "/Users/copumpkin/Sandbox/Haskell/java/test/Test.class"
151170
putStrLn (ppShow $ runGet (get klass) x)
152171

153172

src/Java/ClassFormat/Raw.hs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import qualified Data.ByteString as B
99
import qualified Data.ByteString.Lazy as BL
1010
import qualified Data.Vector as V
1111
import qualified Data.Vector.Unboxed as U
12+
import qualified Data.IntMap as IM
1213

1314
import Control.Lens.TH
1415

@@ -141,7 +142,7 @@ data Entity = Entity { entityAccessFlags :: !Word16, entityName :: !Con2, entity
141142
data Class = Class
142143
{ majorVersion :: {-# UNPACK #-} !Word16
143144
, minorVersion :: {-# UNPACK #-} !Word16
144-
, constantPool :: !(V.Vector Constant)
145+
, constantPool :: !(IM.IntMap Constant)
145146
, classAccessFlags :: {-# UNPACK #-} !Word16
146147
, className :: {-# UNPACK #-} !Con2
147148
, superClassName :: {-# UNPACK #-} !Con2

test/Test.java

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
public class Test {
2+
byte bval = 0x5;
3+
short sval = 0x555;
4+
int ival = 0x555555;
5+
long lval = 0x555555555555l;
6+
float fval = 0.123e10f;
7+
double dval = 0.1234567890123456e250d;
8+
char cval = 'f';
9+
String strval = "oink";
10+
Object objval = new Object();
11+
12+
byte[] baval = new byte[] { 0x1, 0x2, 0x3 };
13+
short[] saval = new short[] { 0x555, 0x666, 0x777 };
14+
int[] iaval = new int[] { 0x555555, 0x666666 };
15+
long[] laval = new long[] { 0x555555555555l };
16+
float[] faval = new float[] { 0.123e10f, 6.0f };
17+
double[] daval = new double[] { 0.1234567890123456e250d };
18+
char[] caval = new char[] { 'f', 'g' };
19+
String[] straval = new String[] { "oink" };
20+
Object[] objaval = new Object[] { new Object() };
21+
22+
static void sVoid() {}
23+
static byte sByte() { return 1; }
24+
static short sShort() { return 1; }
25+
static int sInt() { return 1; }
26+
static long sLong() { return 1; }
27+
static float sFloat() { return 1.0f; }
28+
static double sDouble() { return 1.0; }
29+
static char sChar() { return 'c'; }
30+
static String sString() { return "string"; }
31+
static Object sObject() { return new Object(); }
32+
33+
static void sVoid(int a, double b, char[] c, long d, byte e) {}
34+
static byte sByte(int a, double b, char[] c, long d, byte e) { return 1; }
35+
static short sShort(int a, double b, char[] c, long d, byte e) { return 1; }
36+
static int sInt(int a, double b, char[] c, long d, byte e) { return 1; }
37+
static long sLong(int a, double b, char[] c, long d, byte e) { return 1; }
38+
static float sFloat(int a, double b, char[] c, long d, byte e) { return 1.0f; }
39+
static double sDouble(int a, double b, char[] c, long d, byte e) { return 1.0; }
40+
static char sChar(int a, double b, char[] c, long d, byte e) { return 'c'; }
41+
static String sString(int a, double b, char[] c, long d, byte e) { return "string"; }
42+
static Object sObject(int a, double b, char[] c, long d, byte e) { return new Object(); }
43+
44+
static native int snInt(int x, char y);
45+
static synchronized char ssChar(int x, char y) { return 'e'; }
46+
47+
void iVoid() {}
48+
byte iByte() { return 1; }
49+
short iShort() { return 1; }
50+
int iInt() { return 1; }
51+
long iLong() { return 1; }
52+
float iFloat() { return 1.0f; }
53+
double iDouble() { return 1.0; }
54+
char iChar() { return 'c'; }
55+
String iString() { return "string"; }
56+
Object iObject() { return new Object(); }
57+
58+
protected void iVoid(int a, double b, char[] c, long d, byte e) {}
59+
protected byte iByte(int a, double b, char[] c, long d, byte e) { return 1; }
60+
protected short iShort(int a, double b, char[] c, long d, byte e) { return 1; }
61+
protected int iInt(int a, double b, char[] c, long d, byte e) { return 1; }
62+
protected long iLong(int a, double b, char[] c, long d, byte e) { return 1; }
63+
protected float iFloat(int a, double b, char[] c, long d, byte e) { return 1.0f; }
64+
protected double iDouble(int a, double b, char[] c, long d, byte e) { return 1.0; }
65+
protected char iChar(int a, double b, char[] c, long d, byte e) { return 'c'; }
66+
protected String iString(int a, double b, char[] c, long d, byte e) { return "string"; }
67+
protected Object iObject(int a, double b, char[] c, long d, byte e) { return new Object(); }
68+
69+
@Deprecated int dx = 5;
70+
71+
72+
73+
private static int sPrivateX = 6;
74+
75+
static class InnerStaticSuper {
76+
void bar() { System.out.println("bar"); }
77+
}
78+
79+
static class InnerStaticSub extends InnerStaticSuper {
80+
@Override void bar() { System.out.println("foo"); }
81+
void baz() { sPrivateX++; }
82+
}
83+
84+
85+
private int privateX = 15;
86+
87+
class InnerSuper {
88+
protected void foo() { System.out.println("foo"); }
89+
}
90+
91+
class InnerSub extends InnerSuper {
92+
InnerSub() { privateX++; }
93+
94+
@Override protected void foo() { System.out.println("bar"); }
95+
}
96+
97+
98+
void exceptionCatcher(int x, int y, double a, double b, long v) throws ArrayIndexOutOfBoundsException {
99+
try {
100+
System.out.println("hi!");
101+
102+
while (true) {
103+
try {
104+
System.out.println("oink");
105+
} catch (Throwable t) {
106+
System.out.println("mooooooo");
107+
continue;
108+
} finally {
109+
System.out.println("foo");
110+
break;
111+
}
112+
}
113+
114+
if (x == 5) return;
115+
} catch (Exception e) {
116+
e.printStackTrace();
117+
throw new ArrayIndexOutOfBoundsException(5);
118+
} finally {
119+
System.out.println("bye!");
120+
}
121+
System.out.println("bye!");
122+
}
123+
}

0 commit comments

Comments
 (0)