KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > jode > flow > TransformConstructors


1 /* TransformConstructors Copyright (C) 1998-2002 Jochen Hoenicke.
2  *
3  * This program is free software; you can redistribute it and/or modify
4  * it under the terms of the GNU Lesser General Public License as published by
5  * the Free Software Foundation; either version 2, or (at your option)
6  * any later version.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU Lesser General Public License
14  * along with this program; see the file COPYING.LESSER. If not, write to
15  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
16  *
17  * $Id: TransformConstructors.java,v 1.27.2.5 2002/05/28 17:34:09 hoenicke Exp $
18  */

19
20 package jode.flow;
21 import java.lang.reflect.Modifier JavaDoc;
22 import jode.GlobalOptions;
23 import jode.decompiler.Analyzer;
24 import jode.decompiler.ClassAnalyzer;
25 import jode.decompiler.MethodAnalyzer;
26 import jode.decompiler.FieldAnalyzer;
27 import jode.decompiler.MethodAnalyzer;
28 import jode.decompiler.Options;
29 import jode.decompiler.OuterValues;
30 import jode.decompiler.OuterValueListener;
31 import jode.expr.*;
32 import jode.type.MethodType;
33 import jode.type.Type;
34 import jode.bytecode.ClassInfo;
35 import jode.bytecode.InnerClassInfo;
36 import jode.bytecode.MethodInfo;
37
38 import java.util.Vector JavaDoc;
39 import java.util.Enumeration JavaDoc;
40
41 /**
42  * This class will transform the constructors. We differ three types of
43  * constructors:
44  * <dl><dt>type0</dt>
45  * <dd>are constructors, that call no constructors or whose default super
46  * call was already removed. <code>java.lang.Object.&lt;init&gt;</code>
47  * and static constructors are examples for the first kind.</dd>
48  * <dt>type1</dt>
49  * <dd>are constructors, that call the constructor of super class</dd>
50  * <dt>type2</dt>
51  * <dd>are constructors, that call another constructor of the same class</dd>
52  * </dl>
53  *
54  * The transformation involves several steps:
55  *
56  * The first step is done by removeSynthInitializers, which does the following:
57  * <ul><li>For inner classes check if the this$0 field(s) is/are
58  * initialized corectly, remove the initializer and mark that
59  * field. </li>
60  * <li>For method scope classes also check the val$xx fields.</li>
61  * </ul><br>
62  *
63  * In the last analyze phase (makeDeclaration) the rest is done:
64  * <ul>
65  * <li>remove implicit super() call</li>
66  * <li>move constant field initializations that occur in all constructors
67  * (except those that start with a this() call) to the fields.</li>
68  * <li>For jikes class check for a constructor$xx call, and mark that
69  * as the real constructor, moving the super call of the original
70  * constructor</li>
71  * <li>For anonymous classes check that the constructor only contains
72  * a super call and mark it as default</li></ul>
73  *
74  * It will make use of the <code>outerValues</code> expression, that
75  * tell which parameters (this and final method variables) are always
76  * given to the constructor.
77  *
78  * You can debug this class with the <code>--debug=constructors</code>
79  * switch.
80  *
81  * @author Jochen Hoenicke
82  * @see jode.decompiler.FieldAnalyzer#setInitializer
83  * @see jode.decompiler.ClassAnalyzer#getOuterValues */

84 public class TransformConstructors {
85     /* What is sometimes confusing is the distinction between slot and
86      * parameter. Most times parameter nr = slot nr, but double and
87      * long parameters take two slots, so the remaining parameters
88      * will shift.
89      */

90
91     ClassAnalyzer clazzAnalyzer;
92     boolean isStatic;
93
94     /* The method analyzers of the constructors: type0 constructors
95      * come first, then type1, then type2.
96      */

97     MethodAnalyzer[] cons;
98     int type0Count;
99     int type01Count;
100
101     OuterValues outerValues;
102
103     public TransformConstructors(ClassAnalyzer clazzAnalyzer,
104                  boolean isStatic, MethodAnalyzer[] cons) {
105     this.clazzAnalyzer = clazzAnalyzer;
106     this.isStatic = isStatic;
107     this.cons = cons;
108     if (!isStatic)
109         this.outerValues = clazzAnalyzer.getOuterValues();
110     lookForConstructorCall();
111     }
112     
113     /**
114      * Returns the type of the constructor. We differ three types of
115      * constructors:
116      * <dl><dt>type1</dt>
117      * <dd>are constructors, that call the constructor of super class</dd>
118      * <dt>type2</dt>
119      * <dd>are constructors, that call another constructor of the same
120      * class</dd>
121      * <dt>type0</dt>
122      * <dd>are constructors, that call no constructors.
123      * <code>java.lang.Object.&lt;init&gt;</code> and static constructors
124      * are examples for this</dd>
125      * </dl>
126      * @param body the content of the constructor.
127      * @return the type of the constructor.
128      */

129     private int getConstructorType(StructuredBlock body) {
130     /* A non static constructor must begin with a call to
131      * another constructor. Either to a constructor of the
132      * same class or to the super class */

133     InstructionBlock ib;
134     if (body instanceof InstructionBlock)
135         ib = (InstructionBlock)body;
136     else if (body instanceof SequentialBlock
137          && (body.getSubBlocks()[0]
138              instanceof InstructionBlock))
139         ib = (InstructionBlock) body.getSubBlocks()[0];
140     else
141         return 0;
142     
143     Expression superExpr = ib.getInstruction().simplify();
144     if (!(superExpr instanceof InvokeOperator)
145         || superExpr.getFreeOperandCount() != 0)
146         return 0;
147     InvokeOperator superInvoke = (InvokeOperator) superExpr;
148     if (!superInvoke.isConstructor()
149         || !superInvoke.isSuperOrThis())
150         return 0;
151     Expression thisExpr = superInvoke.getSubExpressions()[0];
152     if (!isThis(thisExpr, clazzAnalyzer.getClazz()))
153         return 0;
154     
155     if (superInvoke.isThis())
156         return 2;
157     else
158         return 1;
159     }
160
161     public void lookForConstructorCall() {
162         type01Count = cons.length;
163         for (int i=0; i< type01Count; ) {
164         MethodAnalyzer current = cons[i];
165         FlowBlock header = cons[i].getMethodHeader();
166         /* Check that code block is fully analyzed */
167         if (header == null || !header.hasNoJumps())
168         return;
169
170         StructuredBlock body = cons[i].getMethodHeader().block;
171         int type = isStatic ? 0 : getConstructorType(body);
172         if ((GlobalOptions.debuggingFlags
173          & GlobalOptions.DEBUG_CONSTRS) != 0)
174         GlobalOptions.err.println("constr "+i+": type"+type+" "+body);
175
176         switch(type) {
177         case 0:
178         // type0 are moved to the beginning.
179
cons[i] = cons[type0Count];
180         cons[type0Count++] = current;
181         /* fall through */
182         case 1:
183         // type1 are not moved at all.
184
i++;
185         break;
186         case 2:
187         // type2 are moved to the end.
188
cons[i] = cons[--type01Count];
189         cons[type01Count] = current;
190         break;
191         }
192     }
193     }
194
195     public static boolean isThis(Expression thisExpr, ClassInfo clazz) {
196     return ((thisExpr instanceof ThisOperator)
197         && (((ThisOperator)thisExpr).getClassInfo() == clazz));
198     }
199
200     /**
201      * Check if this is a single anonymous constructor and mark it as
202      * such. We only check if the super() call is correctly formed and
203      * ignore the rest of the body.
204      *
205      * This method also marks the jikesAnonymousInner.
206      */

207     private void checkAnonymousConstructor() {
208     if (isStatic || cons.length != 1
209         || type01Count - type0Count != 1
210         || clazzAnalyzer.getName() != null)
211         return;
212
213     if ((GlobalOptions.debuggingFlags
214          & GlobalOptions.DEBUG_CONSTRS) != 0)
215         GlobalOptions.err.println("checkAnonymousConstructor of "
216                       +clazzAnalyzer.getClazz());
217
218     StructuredBlock sb = cons[0].getMethodHeader().block;
219     if (sb instanceof SequentialBlock)
220         sb = sb.getSubBlocks()[0];
221
222     InstructionBlock superBlock = (InstructionBlock) sb;
223     /**
224      * Situation:
225      * constructor(outerValues, params) {
226      * super(someOuters, params);
227      * }
228      *
229      * For jikes anonymous classes that extends class or method
230      * scoped classes the situation is more unusal for type1. We
231      * check if this is the case and mark the class as
232      * jikesAnonymousInner:
233      *
234      * constructor(outerValues, params, outerClass) {
235      * outerClass.super(someOuters, params);
236      * constructor$?(outerValues[0], params);
237      * }
238      *
239      * Mark constructor as anonymous constructor. */

240     Expression expr = superBlock.getInstruction().simplify();
241         InvokeOperator superCall = (InvokeOperator) expr;
242     Expression[] subExpr = superCall.getSubExpressions();
243
244     /* An anonymous constructor may only give locals
245      * to its super constructor.
246      */

247     for (int i = 1; i < subExpr.length; i++) {
248         if (!(subExpr[i] instanceof LocalLoadOperator))
249         return;
250     }
251
252     Type[] params = cons[0].getType().getParameterTypes();
253     boolean jikesAnon = false;
254
255     int minOuter = params.length;
256
257     int slot = 1;
258     for (int i = 0; i < params.length - 1; i++)
259         slot += params[i].stackSize();
260
261     /* slot counts from last slot down. */
262
263     int start = 1;
264     if (subExpr.length > 2) {
265         LocalLoadOperator llop = (LocalLoadOperator) subExpr[1];
266
267         if (llop.getLocalInfo().getSlot() == slot) {
268         jikesAnon = true;
269         start++;
270         // This is not an outer value.
271
minOuter--;
272         slot -= params[minOuter - 1].stackSize();
273         }
274     }
275
276     int sub = subExpr.length - 1;
277     /* Check how many parameters are passed correctly. */
278     while (sub >= start) {
279         LocalLoadOperator llop = (LocalLoadOperator) subExpr[sub];
280
281         if ((GlobalOptions.debuggingFlags
282          & GlobalOptions.DEBUG_CONSTRS) != 0)
283         GlobalOptions.err.println(" pos "+sub+": "+slot+","
284                       + llop.getLocalInfo().getSlot()+
285                       "; "+minOuter);
286         
287         if (llop.getLocalInfo().getSlot() != slot) {
288         // restore the slot.
289
slot += params[minOuter - 1].stackSize();
290         break;
291         }
292         sub--;
293         /* This parameter is not forced to be an outer value */
294         minOuter--;
295         if (minOuter == 0)
296         break;
297         slot -= params[minOuter - 1].stackSize();
298     }
299     ClassAnalyzer superAna = superCall.getClassAnalyzer();
300     OuterValues superOV = null;
301     if (superAna != null
302         && superAna.getParent() instanceof MethodAnalyzer) {
303         // super is a method scope class.
304
superOV = superAna.getOuterValues();
305     }
306     int minSuperOuter = sub - start + 1;
307     if ((GlobalOptions.debuggingFlags
308          & GlobalOptions.DEBUG_CONSTRS) != 0)
309         GlobalOptions.err.println(" super outer: " + superOV);
310
311     /* The remaining sub expressions must be outerValues. */
312     for (; sub >= start; sub--) {
313         LocalLoadOperator llop = (LocalLoadOperator) subExpr[sub];
314         if (llop.getLocalInfo().getSlot() >= slot) {
315         if ((GlobalOptions.debuggingFlags
316              & GlobalOptions.DEBUG_CONSTRS) != 0)
317             GlobalOptions.err.println(" Illegal slot at "+sub+":"
318                           + llop.getLocalInfo().getSlot());
319         return;
320         }
321     }
322
323     if (minSuperOuter == 1
324         && superAna.getParent() instanceof ClassAnalyzer) {
325         /* Check if this is the implicit Outer Class */
326         LocalLoadOperator llop = (LocalLoadOperator) subExpr[start];
327         if (outerValues.getValueBySlot(llop.getLocalInfo().getSlot())
328         instanceof ThisOperator) {
329         minSuperOuter = 0;
330         outerValues.setImplicitOuterClass(true);
331         }
332     }
333
334     if (minSuperOuter > 0) {
335         if (superOV == null || superOV.getCount() < minSuperOuter) {
336         if ((GlobalOptions.debuggingFlags
337              & GlobalOptions.DEBUG_CONSTRS) != 0)
338             GlobalOptions.err.println(" super outer doesn't match: "
339                           + minSuperOuter);
340         return;
341         }
342         superOV.setMinCount(minSuperOuter);
343     }
344
345     outerValues.setMinCount(minOuter);
346     if (superOV != null) {
347         final int ovdiff = minOuter - minSuperOuter;
348         outerValues.setCount(superOV.getCount() + ovdiff);
349         superOV.addOuterValueListener(new OuterValueListener() {
350         public void shrinkingOuterValues
351             (OuterValues other, int newCount) {
352             outerValues.setCount(newCount + ovdiff);
353         }
354         });
355     } else
356         outerValues.setCount(minOuter);
357
358     if (jikesAnon)
359         outerValues.setJikesAnonymousInner(true);
360     if ((GlobalOptions.debuggingFlags
361          & GlobalOptions.DEBUG_CONSTRS) != 0)
362         GlobalOptions.err.println(" succeeded: "+outerValues);
363     cons[0].setAnonymousConstructor(true);
364     superBlock.removeBlock();
365     type0Count++;
366     }
367
368     private boolean checkJikesSuper(Expression expr) {
369     if (expr instanceof LocalStoreOperator
370         || expr instanceof IIncOperator)
371         return false;
372     if (expr instanceof Operator) {
373         Expression subExpr[] = ((Operator)expr).getSubExpressions();
374         for (int i=0; i< subExpr.length; i++) {
375         if (!checkJikesSuper(subExpr[i]))
376             return false;
377         }
378     }
379     return true;
380     }
381
382     private Expression renameJikesSuper(Expression expr,
383                     MethodAnalyzer methodAna,
384                     int firstOuterSlot,
385                     int firstParamSlot) {
386     if (expr instanceof LocalLoadOperator) {
387         LocalLoadOperator llop = (LocalLoadOperator) expr;
388         int slot = llop.getLocalInfo().getSlot();
389         if (slot >= firstOuterSlot && slot < firstParamSlot)
390         return outerValues.getValueBySlot(slot);
391         else {
392         Type[] paramTypes = methodAna.getType().getParameterTypes();
393         int param;
394         /* Adjust the slot */
395         if (slot >= firstParamSlot)
396             slot -= firstParamSlot - firstOuterSlot;
397         for (param = 0; slot > 1 && param < paramTypes.length; param++)
398             slot -= paramTypes[param].stackSize();
399         llop.setLocalInfo(methodAna.getParamInfo(1+param));
400         llop.setMethodAnalyzer(methodAna);
401         return llop;
402         }
403     }
404     if (expr instanceof Operator) {
405         Expression subExpr[] = ((Operator)expr).getSubExpressions();
406         for (int i=0; i< subExpr.length; i++) {
407         Expression newSubExpr =
408             renameJikesSuper(subExpr[i], methodAna,
409                      firstOuterSlot, firstParamSlot);
410         if (newSubExpr != subExpr[i])
411             ((Operator)expr).setSubExpressions(i, newSubExpr);
412         }
413     }
414     return expr;
415     }
416
417     public void checkJikesContinuation() {
418     if ((GlobalOptions.debuggingFlags
419          & GlobalOptions.DEBUG_CONSTRS) != 0)
420         System.err.println("checkJikesContinuation: "+outerValues);
421     constr_loop:
422     for (int i=0; i < cons.length; i++) {
423         if ((GlobalOptions.debuggingFlags
424          & GlobalOptions.DEBUG_CONSTRS) != 0)
425         GlobalOptions.err.println("constr "+i+" type"
426                       + (i < type0Count ? 0 :
427                          i < type01Count ? 1 : 2) + " : "
428                       + cons[i].getMethodHeader());
429
430         MethodAnalyzer constr = cons[i];
431         MethodType constrType = constr.getType();
432         
433         /*
434          * constructor(outerValues, params, opt. jikesAnonInner param) {
435          * optional super/this(expressions);
436          * constructor$?(optional outerValues[0], params);
437          * }
438          *
439          * The outerValues[0] parameter is the this local in the
440          * surrounding method. But we can't be sure, what the
441          * surrounding method is, since it could be either the method
442          * that uses the class, or a method that declares the class, that
443          * contains the method that uses the class.<br>
444          *
445          * If the surrounding method is static, the outerValues[0]
446          * parameter disappears.
447          *
448          * Move optional super to method constructor$?
449          * (renaming local variables) and mark constructor and
450          * constructor$? as Jikes constructor. */

451         StructuredBlock sb = constr.getMethodHeader().block;
452         
453         Vector JavaDoc localLoads = null;
454         InstructionBlock superBlock = null;
455         if (i >= type0Count) {
456         /* Extract the super() or this() call at the beginning
457          * of the constructor
458          */

459         if (!(sb instanceof SequentialBlock)
460             || !(sb.getSubBlocks()[1] instanceof InstructionBlock))
461             continue constr_loop;
462
463         superBlock = (InstructionBlock) sb.getSubBlocks()[0];
464         sb = sb.getSubBlocks()[1];
465
466         Expression superExpr = superBlock.getInstruction().simplify();
467         InvokeOperator superInvoke = (InvokeOperator) superExpr;
468         superBlock.setInstruction(superInvoke);
469         
470         Expression[] subExpr = superInvoke.getSubExpressions();
471         for (int j=1; j< subExpr.length; j++) {
472             if (!checkJikesSuper(subExpr[j]))
473             continue constr_loop;
474         }
475         }
476
477         if (!(sb instanceof InstructionBlock))
478         continue constr_loop;
479         
480         /* Now check the constructor$? invocation */
481         Expression lastExpr
482         = ((InstructionBlock)sb).getInstruction().simplify();
483         if (!(lastExpr instanceof InvokeOperator))
484         continue constr_loop;
485         
486         InvokeOperator invoke = (InvokeOperator) lastExpr;
487         if (!invoke.isThis()
488         || invoke.getFreeOperandCount() != 0)
489         continue constr_loop;
490         MethodAnalyzer methodAna = invoke.getMethodAnalyzer();
491         if (methodAna == null)
492         continue constr_loop;
493         MethodType methodType = methodAna.getType();
494         Expression[] methodParams = invoke.getSubExpressions();
495
496         if (!methodAna.getName().startsWith("constructor$")
497         || methodType.getReturnType() != Type.tVoid)
498         continue constr_loop;
499         
500         if (!isThis(methodParams[0], clazzAnalyzer.getClazz()))
501         continue constr_loop;
502         for (int j=1; j < methodParams.length; j++) {
503         if (!(methodParams[j] instanceof LocalLoadOperator))
504             continue constr_loop;
505         }
506     
507         Type[] paramTypes = constr.getType().getParameterTypes();
508         int paramCount = paramTypes.length;
509         if (outerValues.isJikesAnonymousInner())
510         paramCount--;
511
512         int maxOuterCount = paramCount - methodParams.length + 2;
513         int minOuterCount = maxOuterCount - 1;
514         int slot = 1;
515         int firstParam = 1;
516         Expression outer0 = null;
517
518         if (maxOuterCount > 0
519         && methodParams.length > 1
520         && outerValues.getCount() > 0) {
521         /* Check if the outerValues[0] param is present.
522          * we can't be sure if maxOuterCount equals 1, but
523          * we assume so, since at this time all possible
524          * info about outers have been collected.
525          */

526         if (((LocalLoadOperator)methodParams[firstParam]
527              ).getLocalInfo().getSlot() == 1) {
528             minOuterCount = maxOuterCount;
529             outer0 = outerValues.getValue(0);
530             firstParam++;
531         } else
532             maxOuterCount--;
533         for (int j=0; j < maxOuterCount; j++)
534             slot += paramTypes[j].stackSize();
535         }
536
537         if (minOuterCount > outerValues.getCount())
538         continue constr_loop;
539
540         int firstParamSlot = slot;
541         int firstOuterSlot = firstParam;
542         int slotDist = firstParamSlot - firstOuterSlot;
543         /* check the remaining parameters.
544          */

545         for (int j=firstParam; j < methodParams.length; j++) {
546         if (((LocalLoadOperator) methodParams[j]
547              ).getLocalInfo().getSlot() != slot)
548             continue constr_loop;
549         slot += methodParams[j].getType().stackSize();
550         }
551
552         outerValues.setMinCount(minOuterCount);
553         outerValues.setCount(maxOuterCount);
554
555         /* Now move the constructor call.
556          */

557         if (superBlock != null) {
558         Expression newExpr =
559             renameJikesSuper(superBlock.getInstruction(), methodAna,
560                      firstOuterSlot, firstParamSlot);
561         superBlock.removeBlock();
562         methodAna.insertStructuredBlock(superBlock);
563         }
564         if (outer0 != null) {
565         methodAna.getParamInfo(1).setExpression(outer0);
566         methodAna.getMethodHeader().simplify();
567         }
568
569         if ((GlobalOptions.debuggingFlags
570          & GlobalOptions.DEBUG_CONSTRS) != 0)
571         GlobalOptions.err.println(" succeeded");
572
573         constr.setJikesConstructor(constr);
574         methodAna.setJikesConstructor(constr);
575         methodAna.setHasOuterValue(firstOuterSlot == 2);
576         if (constr.isAnonymousConstructor())
577         methodAna.setAnonymousConstructor(true);
578     }
579     }
580
581     /**
582      * This methods checks if expr is a valid field initializer. It
583      * will also merge outerValues, that occur in expr.
584      * @param expr the initializer to check
585      * @return the transformed initializer or null if expr is not valid.
586      */

587     private Expression transformFieldInitializer(int fieldSlot,
588                          Expression expr) {
589     if (expr instanceof LocalVarOperator) {
590         if (!(expr instanceof LocalLoadOperator)) {
591         if ((GlobalOptions.debuggingFlags
592              & GlobalOptions.DEBUG_CONSTRS) != 0)
593             GlobalOptions.err.println("illegal local op: "+expr);
594         return null;
595         }
596         if (outerValues != null
597         && (Options.options & Options.OPTION_CONTRAFO) != 0) {
598         int slot = ((LocalLoadOperator)expr).getLocalInfo().getSlot();
599         Expression outExpr = outerValues.getValueBySlot(slot);
600         if (outExpr != null)
601             return outExpr;
602             }
603         if ((GlobalOptions.debuggingFlags
604          & GlobalOptions.DEBUG_CONSTRS) != 0)
605         GlobalOptions.err.println("not outerValue: "+expr
606                       +" "+outerValues);
607         return null;
608     }
609     if (expr instanceof FieldOperator) {
610         if (expr instanceof PutFieldOperator)
611         return null;
612         FieldOperator fo = (FieldOperator) expr;
613         if (fo.getClassInfo() == clazzAnalyzer.getClazz()
614         && clazzAnalyzer.getFieldIndex(fo.getFieldName(),
615                            fo.getFieldType()) >= fieldSlot)
616         return null;
617     }
618     if (expr instanceof InvokeOperator) {
619         /* Don't allow method invocations that can throw a checked
620          * exception to leave the constructor.
621          */

622         MethodInfo method = ((InvokeOperator) expr).getMethodInfo();
623         String JavaDoc[] excs = method == null ? null : method.getExceptions();
624         if (excs != null) {
625         ClassInfo runtimeException
626             = ClassInfo.forName("java.lang.RuntimeException");
627         ClassInfo error = ClassInfo.forName("java.lang.Error");
628         for (int i = 0; i < excs.length; i++) {
629             ClassInfo exClass = ClassInfo.forName(excs[i]);
630             if (!runtimeException.superClassOf(exClass)
631             && !error.superClassOf(exClass))
632             return null;
633         }
634         }
635     }
636     if (expr instanceof Operator) {
637         Operator op = (Operator) expr;
638         Expression[] subExpr = op.getSubExpressions();
639         for (int i=0; i< subExpr.length; i++) {
640         Expression transformed
641             = transformFieldInitializer(fieldSlot, subExpr[i]);
642         if (transformed == null)
643             return null;
644         if (transformed != subExpr[i])
645             op.setSubExpressions(i, transformed);
646         }
647     }
648     return expr;
649     }
650
651     public void removeSynthInitializers() {
652     if ((Options.options & Options.OPTION_CONTRAFO) == 0
653         || isStatic || type01Count == 0)
654         return;
655
656     checkAnonymousConstructor();
657
658     if ((GlobalOptions.debuggingFlags
659          & GlobalOptions.DEBUG_CONSTRS) != 0)
660         GlobalOptions.err.println("removeSynthInitializers of "
661                       +clazzAnalyzer.getClazz());
662     
663     /* sb will iterate the instructions of the constructor. */
664         StructuredBlock[] sb = new StructuredBlock[type01Count];
665     for (int i=0; i < type01Count; i++) {
666         sb[i] = cons[i].getMethodHeader().block;
667         if (i >= type0Count) {
668         if (sb[i] instanceof SequentialBlock)
669             sb[i] = sb[i].getSubBlocks()[1];
670         else
671             /* One constructor is done. There is no field */
672             return;
673         }
674     }
675     
676     big_loop:
677         for (;;) {
678             StructuredBlock ib =
679                 (sb[0] instanceof SequentialBlock)
680                 ? sb[0].getSubBlocks()[0]
681                 : sb[0];
682
683             if (!(ib instanceof InstructionBlock))
684                 break big_loop;
685
686             Expression instr
687         = ((InstructionBlock) ib).getInstruction().simplify();
688         
689         if (!(instr instanceof StoreInstruction)
690         || instr.getFreeOperandCount() != 0)
691         break big_loop;
692         
693         StoreInstruction store = (StoreInstruction) instr;
694         if (!(store.getLValue() instanceof PutFieldOperator))
695         break big_loop;
696         
697         PutFieldOperator pfo = (PutFieldOperator) store.getLValue();
698         if (pfo.isStatic() != isStatic
699         || pfo.getClassInfo() != clazzAnalyzer.getClazz())
700         break big_loop;
701
702         if (!isThis(pfo.getSubExpressions()[0],
703             clazzAnalyzer.getClazz()))
704         break big_loop;
705
706         int field = clazzAnalyzer.getFieldIndex(pfo.getFieldName(),
707                             pfo.getFieldType());
708         if (field < 0)
709             break big_loop;
710         FieldAnalyzer fieldAna = clazzAnalyzer.getField(field);
711
712         /* Don't check for final. Jikes sometimes omits this attribute.
713          */

714         if (!fieldAna.isSynthetic())
715         break big_loop;
716
717             Expression expr = store.getSubExpressions()[1];
718         expr = transformFieldInitializer(field, expr);
719         if (expr == null)
720         break big_loop;
721
722             for (int i=1; i< type01Count; i++) {
723                 ib = (sb[i] instanceof SequentialBlock)
724                     ? sb[i].getSubBlocks()[0]
725                     : sb[i];
726                 if (!(ib instanceof InstructionBlock)
727                     || !(((InstructionBlock)ib).getInstruction().simplify()
728              .equals(instr))) {
729             if ((GlobalOptions.debuggingFlags
730              & GlobalOptions.DEBUG_CONSTRS) != 0)
731             GlobalOptions.err.println(" constr 0 and "+i
732                           +" differ: "
733                           +instr+"<-/->"+ib);
734                     break big_loop;
735                 }
736             }
737
738
739         if ((GlobalOptions.debuggingFlags
740          & GlobalOptions.DEBUG_CONSTRS) != 0)
741         GlobalOptions.err.println(" field " + pfo.getFieldName()
742                       + " = " + expr);
743
744             if (!(fieldAna.setInitializer(expr))) {
745         if ((GlobalOptions.debuggingFlags
746              & GlobalOptions.DEBUG_CONSTRS) != 0)
747             GlobalOptions.err.println(" setField failed");
748                 break big_loop;
749             }
750         
751             
752         boolean done = false;
753             for (int i=0; i< type01Count; i++) {
754                 if (sb[i] instanceof SequentialBlock) {
755             StructuredBlock next = sb[i].getSubBlocks()[1];
756             next.replace(sb[i]);
757             sb[i] = next;
758         } else {
759             sb[i].removeBlock();
760             sb[i] = null;
761             done = true;
762         }
763             }
764
765         if (done) {
766         if ((GlobalOptions.debuggingFlags
767              & GlobalOptions.DEBUG_CONSTRS) != 0)
768             GlobalOptions.err.println("one constr is over");
769         break;
770         }
771         }
772     }
773
774
775     public int transformOneField(int lastField, StructuredBlock ib) {
776     
777     if (!(ib instanceof InstructionBlock))
778         return -1;
779     
780     Expression instr = ((InstructionBlock) ib).getInstruction().simplify();
781     
782     if (!(instr instanceof StoreInstruction)
783         || instr.getFreeOperandCount() != 0)
784         return -1;
785     
786     StoreInstruction store = (StoreInstruction) instr;
787     if (!(store.getLValue() instanceof PutFieldOperator))
788         return -1;
789     
790     PutFieldOperator pfo = (PutFieldOperator) store.getLValue();
791     if (pfo.isStatic() != isStatic
792         || pfo.getClassInfo() != clazzAnalyzer.getClazz())
793         return -1;
794     
795     if (!isStatic) {
796         if (!isThis(pfo.getSubExpressions()[0],
797             clazzAnalyzer.getClazz())) {
798         if ((GlobalOptions.debuggingFlags
799              & GlobalOptions.DEBUG_CONSTRS) != 0)
800             GlobalOptions.err.println(" not this: "+instr);
801         return -1;
802         }
803     }
804     
805     int field = clazzAnalyzer.getFieldIndex(pfo.getFieldName(),
806                         pfo.getFieldType());
807
808     if (field <= lastField)
809         return -1;
810
811     Expression expr = store.getSubExpressions()[1];
812     expr = transformFieldInitializer(field, expr);
813     if (expr == null)
814         return -1;
815     
816     if ((GlobalOptions.debuggingFlags
817          & GlobalOptions.DEBUG_CONSTRS) != 0)
818         GlobalOptions.err.println(" field " + pfo.getFieldName()
819                       + " = " + expr);
820     
821     // if field does not exists: -1 <= lastField.
822
if (field <= lastField
823         || !(clazzAnalyzer.getField(field).setInitializer(expr))) {
824         if ((GlobalOptions.debuggingFlags
825          & GlobalOptions.DEBUG_CONSTRS) != 0)
826         GlobalOptions.err.println("set field failed");
827         return -1;
828     }
829     return field;
830     }
831     
832     public void transformBlockInitializer(StructuredBlock block) {
833     StructuredBlock start = null;
834     StructuredBlock tail = null;
835     int lastField = -1;
836     while (block instanceof SequentialBlock) {
837         StructuredBlock ib = block.getSubBlocks()[0];
838         int field = transformOneField(lastField, ib);
839         if (field < 0)
840         clazzAnalyzer.addBlockInitializer(lastField + 1, ib);
841         else
842         lastField = field;
843         block = block.getSubBlocks()[1];
844     }
845     if (transformOneField(lastField, block) < 0)
846         clazzAnalyzer.addBlockInitializer(lastField + 1, block);
847     }
848
849     public boolean checkBlockInitializer(InvokeOperator invoke) {
850     if (!invoke.isThis()
851         || invoke.getFreeOperandCount() != 0)
852         return false;
853     MethodAnalyzer methodAna = invoke.getMethodAnalyzer();
854     if (methodAna == null)
855         return false;
856     FlowBlock flow = methodAna.getMethodHeader();
857     MethodType methodType = methodAna.getType();
858     if (!methodAna.getName().startsWith("block$")
859         || methodType.getParameterTypes().length != 0
860         || methodType.getReturnType() != Type.tVoid)
861         return false;
862     if (flow == null || !flow.hasNoJumps())
863         return false;
864
865     if (!isThis(invoke.getSubExpressions()[0],
866             clazzAnalyzer.getClazz()))
867         return false;
868
869     methodAna.setJikesBlockInitializer(true);
870     transformBlockInitializer(flow.block);
871     return true;
872     }
873
874     private void removeDefaultSuper() {
875     if ((GlobalOptions.debuggingFlags
876          & GlobalOptions.DEBUG_CONSTRS) != 0)
877         GlobalOptions.err.println("removeDefaultSuper of "
878                       + clazzAnalyzer.getClazz());
879     /* Check if we can remove the super() call of type1 constructors.
880      * This transforms a type1 constructor in a type0 constructor.
881      */

882         for (int i=type0Count; i< type01Count; i++) {
883         MethodAnalyzer current = cons[i];
884         FlowBlock header = cons[i].getMethodHeader();
885             StructuredBlock body = header.block;
886         
887         if ((GlobalOptions.debuggingFlags
888          & GlobalOptions.DEBUG_CONSTRS) != 0)
889         GlobalOptions.err.println("constr "+i+": "+body);
890
891         InstructionBlock ib;
892         if (body instanceof InstructionBlock)
893         ib = (InstructionBlock) body;
894         else
895         ib = (InstructionBlock) body.getSubBlocks()[0];
896         
897         InvokeOperator superInvoke = (InvokeOperator)
898         ib.getInstruction().simplify();
899         ClassInfo superClazz = superInvoke.getClassInfo();
900         InnerClassInfo[] outers = superClazz.getOuterClasses();
901         int superParamCount = superInvoke.getSubExpressions().length - 1;
902
903         if ((Options.options & Options.OPTION_INNER) != 0
904         && outers != null
905         && outers[0].outer != null
906         && outers[0].name != null
907         && !Modifier.isStatic(outers[0].modifiers)) {
908
909         if (superParamCount != 1
910             || !(superInvoke.getSubExpressions()[1]
911              instanceof ThisOperator))
912             continue;
913         } else {
914         /* If the super() has no parameters (or only default
915          * outerValue parameter for inner/anonymous classes), we
916          * can remove it
917          */

918         ClassAnalyzer superClazzAna = superInvoke.getClassAnalyzer();
919         OuterValues superOV = null;
920         if (superClazzAna != null)
921             superOV = superClazzAna.getOuterValues();
922         if (superParamCount > 0
923             && (superOV == null
924             || superParamCount > superOV.getCount()))
925             continue;
926         }
927         ib.removeBlock();
928         if (i > type0Count) {
929         cons[i] = cons[type0Count];
930         cons[type0Count] = current;
931         }
932         type0Count++;
933     }
934     }
935
936     private void removeInitializers() {
937     if (type01Count == 0)
938         return;
939
940     if ((GlobalOptions.debuggingFlags
941          & GlobalOptions.DEBUG_CONSTRS) != 0)
942         GlobalOptions.err.println("removeInitializers");
943     
944         StructuredBlock[] sb = new StructuredBlock[type01Count];
945         for (int i=0; i< type01Count; i++) {
946         FlowBlock header = cons[i].getMethodHeader();
947         /* sb[i] will iterate the instructions of the constructor. */
948             sb[i] = header.block;
949             if (i >= type0Count) {
950                 if (sb[i] instanceof SequentialBlock)
951                     sb[i] = sb[i].getSubBlocks()[1];
952                 else {
953                     sb[i] = null;
954             return;
955         }
956             }
957         }
958     int lastField = -1;
959     big_loop:
960         for (;;) {
961             StructuredBlock ib =
962                 (sb[0] instanceof SequentialBlock)
963                 ? sb[0].getSubBlocks()[0]
964                 : sb[0];
965
966         if ((GlobalOptions.debuggingFlags
967          & GlobalOptions.DEBUG_CONSTRS) != 0)
968         GlobalOptions.err.println("Instruction: "+ib);
969
970             if (!(ib instanceof InstructionBlock))
971                 break big_loop;
972
973             Expression instr
974         = ((InstructionBlock) ib).getInstruction().simplify();
975
976             for (int i=1; i < type01Count; i++) {
977                 ib = (sb[i] instanceof SequentialBlock)
978                     ? sb[i].getSubBlocks()[0]
979                     : sb[i];
980                 if (!(ib instanceof InstructionBlock)
981                     || !(((InstructionBlock)ib).getInstruction().simplify()
982              .equals(instr))) {
983             if ((GlobalOptions.debuggingFlags
984              & GlobalOptions.DEBUG_CONSTRS) != 0)
985             GlobalOptions.err.println("constr "+i+" differs: "+ib);
986                     break big_loop;
987                 }
988             }
989
990         if (instr instanceof InvokeOperator
991         && checkBlockInitializer((InvokeOperator) instr)) {
992         for (int i=0; i< type01Count; i++) {
993             if (sb[i] instanceof SequentialBlock) {
994             StructuredBlock next = sb[i].getSubBlocks()[1];
995             next.replace(sb[i]);
996             sb[i] = next;
997             } else {
998             sb[i].removeBlock();
999             sb[i] = null;
1000            }
1001        }
1002        break big_loop;
1003        }
1004        
1005        int field = transformOneField(lastField, ib);
1006        if (field < 0)
1007        break big_loop;
1008
1009        lastField = field;
1010
1011        boolean done = false;
1012            for (int i=0; i< type01Count; i++) {
1013                if (sb[i] instanceof SequentialBlock) {
1014            StructuredBlock next = sb[i].getSubBlocks()[1];
1015            next.replace(sb[i]);
1016            sb[i] = next;
1017        } else {
1018            sb[i].removeBlock();
1019            sb[i] = null;
1020            done = true;
1021        }
1022            }
1023
1024        if (done) {
1025        if ((GlobalOptions.debuggingFlags
1026             & GlobalOptions.DEBUG_CONSTRS) != 0)
1027            GlobalOptions.err.println("one constr is over");
1028        break;
1029        }
1030        }
1031    }
1032
1033    /**
1034     * This does the normal constructor transformations.
1035     *
1036     * javac copies the field initializers to each constructor. This
1037     * will undo the transformation: it will tell the fields about the
1038     * initial value and removes the initialization from all constructors.
1039     *
1040     * There are of course many checks necessary: All field
1041     * initializers must be equal in all constructors, and there
1042     * mustn't be locals that used in field initialization (except
1043     * outerValue - locals).
1044     */

1045    public void transform() {
1046    if ((Options.options & Options.OPTION_CONTRAFO) == 0
1047        || cons.length == 0)
1048        return;
1049
1050    removeDefaultSuper();
1051    removeInitializers();
1052    checkJikesContinuation();
1053
1054    if (outerValues != null) {
1055        /* Now tell all constructors the value of outerValues parameters
1056         * and simplify them again.
1057         */

1058        for (int i=0; i< cons.length; i++) {
1059        for (int j = 0; j < outerValues.getCount(); j++)
1060            cons[i].getParamInfo(j+1)
1061            .setExpression(outerValues.getValue(j));
1062        // if (outerValues.isJikesAnonymousConstructor()) {
1063
// /*XXX???*/
1064
// }
1065
cons[i].getMethodHeader().simplify();
1066        }
1067    }
1068    }
1069}
1070
Popular Tags