759db9ce1fbdb1eabbd415a18707627d25c8e175
[org.ibex.classgen.git] / src / org / ibex / classgen / opt / Arena.java
1 package org.ibex.classgen.opt;
2 import java.io.*;
3 import java.util.*;
4 import org.ibex.classgen.*;
5 import java.io.*;
6 import java.util.*;
7 import java.util.zip.*;
8
9 public class Arena implements CGConst {
10
11     public static interface Gladiator { }
12
13     Context cx = new Context();
14
15     public static final int initialSize = 1000;
16
17
18     // Initializers //////////////////////////////////////////////////////////////////////////////
19
20     public static Type.Class        System_class     = Type.Class.instance("java.lang.System");
21     public static Type.Class.Method System_arraycopy = System_class.method("arraycopy","(Ljava/lang/Object;ILjava/lang/Object;II)V");
22     public static Type.Class        Gladiator_class  = Type.Class.instance("org.ibex.classgen.opt.Arena$Gladiator");
23
24     boolean          implementsGladiator(Type t)          { return t instanceof Type.Class && implementsGladiator((Type.Class)t);}
25     boolean          implementsGladiator(Type.Class c)    { return c.extendsOrImplements(Gladiator_class, cx); }
26
27     String           getArenaName(Type.Class c)           { return c.getName().substring(0, c.getName().lastIndexOf('$')); }
28     String           getGladiatorName(Type.Class c)       { return c.getName().substring(c.getName().lastIndexOf('$')+1); }
29     Type.Class       getArenaForGladiator(Type.Class c)   { return Type.Class.instance(getArenaName(c)); }
30
31     Type             getSliceElementType(Type t)          { return implementsGladiator(t) ? Type.INT : t; }
32     Type.Class.Field getSliceForField(Type.Class.Field f) {
33         Type.Class c = f.getDeclaringClass();
34         return getArenaForGladiator(c).field(getGladiatorName(c)+"$$"+f.getName(),
35                                              getSliceElementType(f.getType()).makeArray());
36     }
37
38
39     // Operations performed on the Gladiator class //////////////////////////////////////////////////////////////////////////
40
41     public Type.Class.Method.Body getSoleConstructor(Type.Class c) {
42         Type.Class.Method.Body ret = null;
43         Type.Class.Method.Body[] bodies = c.getBody(cx).methods();
44         for(int i=0; i<bodies.length; i++) {
45             if (!bodies[i].getMethod().isConstructor()) continue;
46             if (ret != null) throw new Error("class " + c.getName() + " has two constructors");
47             ret = bodies[i];
48         }
49         return ret;
50     }
51
52     public void processGladiatorClass(Type.Class c) {
53
54         System.out.println("**** " + c.getName() + " is a gladiator!");
55
56         Type.Class             arena           = getArenaForGladiator(c);
57         Type.Class.Body        arenaBody       = arena.getBody(cx);
58         MethodGen              arenaInitBody   = (MethodGen)getSoleConstructor(c);
59         Type.Class.Method      arenaInit       = arenaInitBody.getMethod();
60         Type.Class.Field       outerClassField = c.field("this$0", arena);
61
62         Type.Class.Field            maxField = arena.field(getGladiatorName(c) + "$$max", Type.INT);
63         /*arenaBody.addField(maxField, PRIVATE);*/
64         arenaInitBody.insertBlank(0);
65         arenaInitBody.insertBlank(0);
66         arenaInitBody.insertBlank(0);
67         arenaInitBody.set(0, ALOAD_1);
68         arenaInitBody.set(1, LDC, initialSize);
69         arenaInitBody.set(2, PUTFIELD, maxField);
70
71         Type.Class.Field sizeField = arena.field(getGladiatorName(c) + "$$size", Type.INT);
72         /*arenaBody.addField(sizeField, PRIVATE);*/
73         arenaInitBody.insertBlank(0);
74         arenaInitBody.insertBlank(0);
75         arenaInitBody.insertBlank(0);
76         arenaInitBody.set(0, ALOAD_1);
77         arenaInitBody.set(1, LDC, 0);
78         arenaInitBody.set(2, PUTFIELD, sizeField);
79
80         Type.Class.Method      incMethod = null; //c.method(getGladiatorName(c) + "$$inc()I");
81         MethodGen              incBody   = cx.resolve(c.getName()).addMethod(incMethod, PUBLIC);
82         incBody.add(ALOAD_0);
83         incBody.add(GETFIELD, outerClassField);
84         incBody.add(DUP);
85         incBody.add(GETFIELD, sizeField);
86         incBody.add(DUP);
87         incBody.add(ISTORE_1);
88         incBody.add(LDC, 1);
89         incBody.add(IADD);
90         incBody.add(PUTFIELD, sizeField);
91         // FIXME: check for overflow / maxField
92
93         // Finally, iterate over the Gladiator's fields, updating the $$inc method and Arena's zero-arg constructor as we go
94
95         ClassFile cb = cx.resolve(c);
96         Type.Class.Field.Body[] fields = cb.fields();
97         for(int i=0; i<fields.length; i++) {
98             Type.Class.Field f = fields[i].getField();
99             if (f.getName().startsWith("this$")) continue;
100             Type t = getSliceElementType(f.getType());
101             f = arena.field(getGladiatorName(c) + "$$" + f.getName(), t.makeArray());
102             //arenaBody.addField(f, PUBLIC);
103             
104             arenaInitBody.insertBlank(0);
105             arenaInitBody.insertBlank(0);
106             arenaInitBody.insertBlank(0);
107             arenaInitBody.insertBlank(0);
108             arenaInitBody.set(0, ALOAD_1);
109             arenaInitBody.set(1, LDC, initialSize);
110             arenaInitBody.set(2, (t instanceof Type.Ref) ? ANEWARRAY : NEWARRAY, t);
111             arenaInitBody.set(3, PUTFIELD, f);
112         }
113
114         /*
115         for(Iterator it = c.getBody(cx).getMethods().iterator(); it.hasNext();) {
116             Type.Class.Method m = (Type.Class.Method)it.next();
117             if (!m.isConcrete()) continue;
118             boolean doremove = true;
119             Type.Class.Method.Body mincBody = m.getBody(cx);
120             if (implementsGladiator(m.getDeclaringClass()) && m.isConstructor()) {
121                 System.out.println("processing ctor " + c.getName() + "." + m.getSignature());
122                 doremove = false;
123                 Type.Class c = m.getDeclaringClass();
124                 String name = "$init";
125                 Type[] at = m.getArgTypes();
126                 c.removeMethod(m);
127                 Type.Class.Method nm = c.method(name, implementsGladiator(m.getReturnType()) ? Type.INT : m.getReturnType(), at);
128                 Type.Class.Method.Body bod = nm.getBody(cx);
129                 bod.importBodyContentsFrom(m.getActiveBody());
130                 m = nm;
131                 mincBody = bod;
132
133                 for(Iterator it2 = mincBody.getUnits().snapshotIterator(); it2.hasNext(); ) {
134                     Unit u = (Unit)it2.next();
135                     if (u instanceof DefinitionStmt) {
136                         DefinitionStmt ds = (DefinitionStmt)u;
137                         if (ds.getLeftOp() instanceof ThisRef)
138                             mincBody.getUnits().remove(u);
139                         else if (ds.getLeftOp() instanceof FieldRef) {
140                             if (((FieldRef)ds.getLeftOp()).getFieldRef().name().endsWith("this$0"))
141                                 mincBody.getUnits().remove(u);
142                         }
143                     } else if (u instanceof InvokeStmt) {
144                         InvokeExpr ie = ((InvokeStmt)u).getInvokeExpr();
145                         Type.Class.MethodRef meth = ie.getMethodRef();
146                         if (meth.getDeclaringClass().getName().equals("java.lang.Object") && meth.name().equals("<init>"))
147                             mincBody.getUnits().remove(u);
148                     }
149                 }
150             }
151             if (m.isStatic()) continue;
152
153             String name = c.getShortName().substring(c.getShortName().lastIndexOf('$')+1) + "$$" + m.getName();
154             Type[] list = new Type[m.getNumArgs() + 1];
155             for(int i=0; i<m.getNumArgs(); i++) list[i] = m.getArgType(i);
156             list[list.length-1] = Type.INT;
157             Type.Class.Method m2 = c.method(name, m.getReturnType(), list);
158             getArenaForGladiator(c).addMethod(m2);
159             Type.Class.Method.Body ab = m2.getBody(cx);
160             ab.importBodyContentsFrom(mincBody);
161
162             Local loc = Jimple.v().newLocal("tmpRef" + (tfr++), getArenaForGladiator(sc).getType());
163             ab.getLocals().add(loc);
164             // FIXME: insert assignment to this
165             for(Iterator z = ab.getLocals().iterator(); z.hasNext();) {
166                 Local loc2 = (Local)z.next();
167                 if (implementsGladiator(loc2.getType())) {
168                     loc2.setType(IntType.v());
169                 }
170             }
171             Chain units = ab.getUnits();
172             boolean touched = false;
173             Local loc0 = Jimple.v().newLocal("tmpRef" + (tfr++), getArenaForGladiator(sc).getType());
174             ab.getLocals().add(loc0);
175             for(Iterator stmtIt = units.snapshotIterator(); stmtIt.hasNext();) {
176                 Stmt s = (Stmt) stmtIt.next();
177                 if (s instanceof IdentityStmt) {
178                     IdentityStmt is = (IdentityStmt)s;
179                     Local left = (Local)is.getLeftOp();
180                     if (is.getRightOp() instanceof ThisRef) {
181                         left.setType(IntType.v());
182                         is.getRightOpBox().setValue(Jimple.v().newParameterRef(IntType.v(), m.getParameterCount()));
183                         if (!touched) {
184                             units.addFirst(Jimple.v().newIdentityStmt(loc0, Jimple.v().newThisRef(getArenaForGladiator(sc).getType())));
185                             touched = true;
186                         }
187                     }
188                 }
189
190                 for(Iterator i = s.getUseAndDefBoxes().iterator(); i.hasNext();) {
191                     Object o = i.next();
192                     if (o instanceof ValueBox) {
193                         ValueBox vb = (ValueBox)o;
194                         o = vb.getValue();
195                         //if (o instanceof Local && implementsGladiator(((Local)o).getType())) {
196                         //System.out.println("thunking");
197                         //vb.setValue(loc0);
198                         //}
199                         if (vb.getValue() instanceof ThisRef) {
200                             vb.setValue(loc);
201                         }
202                     }
203                 }
204
205             }
206             
207             if (doremove) sc.removeMethod(m);
208
209         }
210         incBody.getUnits().add(returnStmt);
211         */
212         incBody.add(ILOAD_1);
213         incBody.add(IRETURN);
214     }
215
216     // Operations performed on all classes ////////////////////////////////////////////////////////////////////////////
217
218     public Type processType(Type t) {
219         if (t instanceof Type.Array) return processType(((Type.Array)t).getElementType()).makeArray();
220         if (implementsGladiator(t)) return Type.INT;
221         return t;
222     }
223
224     public void processField(Type.Class.Field.Body fb) {
225         /*
226         f.setType(processType(f.getType()));
227         */
228     }
229
230     public void processMethod(Type.Class.Method.Body mb) {
231         /*
232         if (m.getName().endsWith("$$inc")) continue;
233         //if (m.isConcrete()) b = processBody(m.getBody(cx), c, m);
234         m.setReturnType(processType(m.getReturnType()));
235         Type[] argTypes = m.getArgTypes();
236         for(int i=0; i<argTypes.length; i++) argTypes[i] = processType(argTypes[i]);
237         m.setArgTypes(argTypes);
238         
239         if (implementsGladiator(t)) {
240             t = IntType.v();
241             if (m.hasActiveBody()) {
242                 Body bod = m.getActiveBody();
243                 for(Iterator stmtIt = bod.getUnits().snapshotIterator(); stmtIt.hasNext();) {
244                     Stmt s = (Stmt) stmtIt.next();
245                     if (s instanceof ReturnStmt) {
246                         if (((ReturnStmt)s).getOp().getType() instanceof NullType) {
247                             ((ReturnStmt)s).getOpBox().setValue(IntConstant.v(-1));
248                         }
249                     }
250                 }
251             }
252         }
253         c.removeMethod(m);
254         c.addMethod(meth);
255         */
256     }
257
258     public void processClassFile(ClassFile cf) {
259         boolean verdict = implementsGladiator(cf.getType());
260         //System.out.println("checking " + cf.getType().getName() + " => " + verdict);
261         if (verdict) processGladiatorClass(cf.getType());
262         Type.Class.Field.Body[] fields = cf.fields();
263         for(int i=0; i<fields.length; i++) processField(fields[i]);
264         Type.Class.Method.Body[] methods = cf.methods();
265         for(int i=0; i<methods.length; i++) processMethod(methods[i]);
266     }
267
268     /*
269     protected Body processBody(Body body, Type.Class ownerClass, Type.Class.Method smeth) {
270         Chain units = body.getUnits();
271         for(Iterator it = body.getLocals().snapshotIterator(); it.hasNext();) {
272             Local l = (Local)it.next();
273             if (implementsGladiator(l.getType())) l.setType(IntType.v());
274         }
275         if (!smeth.isStatic())
276             body.getThisLocal().setType(ownerClass.getType());
277         for(int qq=0; qq<2; qq++) for(Iterator stmtIt = units.snapshotIterator(); stmtIt.hasNext();) {
278             Stmt s = (Stmt) stmtIt.next();
279             if (s instanceof DefinitionStmt) {
280                 DefinitionStmt ds = (DefinitionStmt)s;
281                 if (ds.getLeftOp().getType() instanceof PrimType && ds.getRightOp().getType() instanceof NullType)
282                     ds.getRightOpBox().setValue(IntConstant.v(-1));
283             }
284             if (implementsGladiator(smeth.getReturnType()) && s instanceof ReturnStmt)
285                 if (((ReturnStmt)s).getOp().getType() instanceof NullType)
286                     ((ReturnStmt)s).getOpBox().setValue(IntConstant.v(-1));
287             List l = s.getUseAndDefBoxes();
288             List l2l = new LinkedList();
289             l2l.addAll(l);
290             for(Iterator it = l2l.iterator(); it.hasNext();) {
291                 Object o = it.next();
292                 if (o instanceof ValueBox) {
293                     ValueBox vb = (ValueBox)o;
294                     Value v = vb.getValue();
295                     
296                     if (v instanceof BinopExpr) {
297                         BinopExpr boe = (BinopExpr)v;
298                         Type t1 = boe.getOp1().getType();
299                         Type t2 = boe.getOp2().getType();
300                         if (t1 instanceof PrimType && t2 instanceof NullType) boe.setOp2(IntConstant.v(-1));
301                         if (t2 instanceof PrimType && t1 instanceof NullType) boe.setOp1(IntConstant.v(-1));
302                     }
303
304                     if (v instanceof NewExpr) {
305                         NewExpr ne = (NewExpr)v;
306                         if (implementsGladiator(ne.getBaseType())) {
307                             Type.Class sc = ((Type.Ref)ne.getBaseType()).Type.Class.instance();
308                             Type.Class arena = getArenaForGladiator(sc);
309                             String incFuncName = sc.getShortName().substring(sc.getShortName().lastIndexOf('$')+1) + "$$inc";
310                             Type.Class.MethodRef smr = Scene.v().makeMethodRef(arena, incFuncName, new LinkedList(), IntType.v(), false);
311                             Expr invokeExpr = Jimple.v().newSpecialInvokeExpr(body.getThisLocal(), smr);
312                             Local ll = viaLocal(invokeExpr, body, s);
313                             vb.setValue(ll);
314                             v = ll;
315                             qq = 0;
316                             break;
317                         } 
318                     } else
319
320                     if (v instanceof InvokeExpr) {
321                         InvokeExpr ie = (InvokeExpr)v;
322                         Type.Class.MethodRef mr = ie.getMethodRef();
323                         String name = mr.name();
324                         if (v instanceof InstanceInvokeExpr && implementsGladiator(mr.getDeclaringClass())) {
325                             InstanceInvokeExpr iie = (InstanceInvokeExpr)v;
326                             List li = new LinkedList();
327                             li.addAll(iie.getArgs());
328                             LinkedList pl = new LinkedList();
329                             for(Iterator it2 = mr.parameterTypes().iterator(); it2.hasNext();) {
330                                 Type t = (Type)it2.next();
331                                 pl.add(implementsGladiator(t) ? IntType.v() : t);
332                             }
333                             if (mr.name().equals("<init>") && implementsGladiator(mr.getDeclaringClass())) {
334                                 name = "$init";
335                                 //li.remove(0);
336                                 //pl.remove(0);
337                             }
338                             pl.add(IntType.v());
339                             //li.add(iie.getBase());
340                             Type.Class sc = mr.getDeclaringClass();
341                             name = sc.getShortName().substring(sc.getShortName().lastIndexOf('$')+1) + "$$" + name;
342                             mr = Scene.v().makeMethodRef(getArenaForGladiator(sc),
343                                                          name,
344                                                          pl,
345                                                          implementsGladiator(mr.returnType()) ? IntType.v() : mr.returnType(),
346                                                          false);
347                             ie = Jimple.v().newVirtualInvokeExpr(body.getThisLocal(), mr, li);
348                             vb.setValue(v = ie);
349
350                         } else if (!(v instanceof StaticInvokeExpr)) {
351                             List l0 = mr.parameterTypes();
352                             List l2 = new LinkedList();
353                             for(Iterator it2 = l0.iterator(); it2.hasNext();) {
354                                 Type t = (Type)it2.next();
355                                 l2.add(implementsGladiator(t) ? IntType.v() : t);
356                             }
357                             mr = Scene.v().makeMethodRef(mr.getDeclaringClass(),
358                                                          mr.name(),
359                                                          l2,
360                                                          implementsGladiator(mr.returnType()) ? IntType.v() : mr.returnType(),
361                                                          mr.isStatic());
362                             ie.setMethodRef(mr);
363                             vb.setValue(v = ie);                            
364                         }
365
366                         for(int i=0; i<ie.getArgCount(); i++) {
367                             ValueBox b = ie.getArgBox(i);
368                             Value val = b.getValue();
369                             if (mr.parameterType(i) instanceof Type.Ref && val.getType() instanceof PrimType) {
370                                 Type.Class intClass = Scene.v().Type.Class.instance("java.lang.Integer");
371                                 List typelist = new LinkedList();
372                                 typelist.add(IntType.v());
373                                 Type.Class.Method intMethod = intClass.getMethod("<init>", typelist);
374                                 Local loc = viaLocal(Jimple.v().newNewExpr(Type.Ref.v(intClass)), body, s);
375                                 List list = new LinkedList();
376                                 list.add(val);
377                                 units.insertBefore(Jimple.v().newInvokeStmt(Jimple.v().newSpecialInvokeExpr(loc,
378                                                                                                             intMethod.makeRef(),
379                                                                                                             list)),
380                                                    s);
381                                 b.setValue(loc);
382                             }
383                             if (val != null && val.getType() instanceof NullType && mr.parameterType(i) instanceof IntType) {
384                                 b.setValue(IntConstant.v(-1));
385                             }
386                         }
387
388
389                     } else if (v instanceof CastExpr) {
390                         CastExpr ce = (CastExpr)v;
391                         if (implementsGladiator(ce.getCastType())) {
392                             Type.Class arena = getArenaForGladiator(((Type.Ref)ce.getCastType()).Type.Class.instance());
393                             Type.Class ic = Scene.v().Type.Class.instance("java.lang.Integer");
394                             ce.setCastType(ic.getType());
395
396                             Local l1 = Jimple.v().newLocal("tmpRef" + (tfr++), ic.getType()); body.getLocals().add(l1);
397                             Local l2 = Jimple.v().newLocal("tmpRef" + (tfr++), IntType.v()); body.getLocals().add(l2);
398
399                             Stmt s2 = Jimple.v().newAssignStmt(l1, Jimple.v().newCastExpr(ce.getOp(), ic.getType()));
400                             body.getUnits().insertBefore(s2, s);
401
402                             Stmt isNull = Jimple.v().newAssignStmt(l2, IntConstant.v(-1));
403                             body.getUnits().insertAfter(isNull, s2);
404
405                             Stmt ifStmt = Jimple.v().newIfStmt(Jimple.v().newEqExpr(l1, NullConstant.v()), s);
406                             body.getUnits().insertAfter(ifStmt, isNull);
407
408                             Type.Class.MethodRef mr = Scene.v().makeMethodRef(ic, "intValue", new LinkedList(), IntType.v(), false);
409                             Stmt isNotNull =
410                                 Jimple.v().newAssignStmt(l2, Jimple.v().newVirtualInvokeExpr(l1, mr, new LinkedList()));
411                             body.getUnits().insertAfter(isNotNull, ifStmt);
412
413                             vb.setValue(l2);
414                             qq = 0;  // ???
415                             break;
416                         }
417
418                     } else if (v instanceof FieldRef) {
419                         FieldRef ifr = (FieldRef)v;
420                         Type.Class.Field fr = ifr.getFieldRef();
421                         Type t = fr.type();
422                         if (implementsGladiator(fr.getDeclaringClass()) && fr.name().equals("this$0")) {
423                             vb.setValue(body.getThisLocal());
424                         } else if (implementsGladiator(fr.getDeclaringClass())) {
425                             Type.Class arena = getArenaForGladiator(fr.getDeclaringClass());
426                             if (fr.isStatic()) {
427                                 vb.setValue(newIFR(body, getSliceForField(fr)));
428                             } else {
429                                 InstanceFieldRef sfr = newIFR(body, getSliceForField(fr));
430                                 vb.setValue(Jimple.v().newArrayRef(viaLocal(sfr, body, s), ((InstanceFieldRef)ifr).getBase()));
431                             }
432                         }
433                         if ((t instanceof Type.Ref) && implementsGladiator(((Type.Ref)t).Type.Class.instance())) {
434                             Type.Class tc = ((Type.Ref)t).Type.Class.instance();
435                             Type.Class arena = getArenaForGladiator(tc);
436                             ifr.setFieldRef(Scene.v().makeFieldRef(arena, fr.name(), IntType.v(), fr.isStatic()));
437                         } else if (t instanceof Type.Array) {
438                             Type.Array at = (Type.Array)t;
439                             Type et = at.getElementType();
440                             if (et instanceof Type.Ref && implementsGladiator(((Type.Ref)et).Type.Class.instance()))
441                                 ifr.setFieldRef(Scene.v().makeFieldRef(fr.getDeclaringClass(),
442                                                                        fr.name(),
443                                                                        IntType.v().makeType.Array(),
444                                                                        fr.isStatic()));
445                         }
446                     }
447
448                 }
449             }
450         }
451         return body;
452     }
453 */
454
455     public static void main(String[] s) throws Exception { new Arena().process(s); }
456     public void process(String[] s) throws Exception {
457         File outf = new File(s[0] + "-");
458         File inf = new File(s[0]);
459         ZipOutputStream out = new ZipOutputStream(new FileOutputStream(outf));
460         ZipInputStream zis = new ZipInputStream(new FileInputStream(inf));
461         for(;;) {
462             ZipEntry ze = zis.getNextEntry();
463             if (ze==null) break;
464             String name = ze.getName();
465             if (!name.endsWith(".class")) {
466                 out.putNextEntry(ze);
467                 byte b[] = new byte[1024];
468                 for(;;) {
469                     int numread = zis.read(b, 0, b.length);
470                     if (numread==-1) break;
471                     out.write(b, 0, numread);
472                 }
473                 continue;
474             }
475             System.out.println("updating " + name.substring(0, name.length()-6).replace('$','.').replace('/','.'));
476             ClassFile cf = new ClassFile(new DataInputStream(zis));
477             cx.add(cf);
478         }
479         for(Iterator it = cx.enumerateClassFiles().iterator(); it.hasNext();) {
480             ClassFile cf = (ClassFile)it.next();
481             System.out.println("processing " + cf.getType());
482             processClassFile(cf);
483         }
484         for(Iterator it = cx.enumerateClassFiles().iterator(); it.hasNext();) {
485             ClassFile cf = (ClassFile)it.next();
486             System.out.println("dumping " + cf.getType());
487             out.putNextEntry(new ZipEntry(cf.getType().getName().replace('.', '/') + ".class"));
488             cf.dump(out);
489         }
490         out.close();
491         outf.renameTo(inf);
492     }
493
494 }