KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > jode > jvm > SyntheticAnalyzer


1 /* SyntheticAnalyzer Copyright (C) 1999-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: SyntheticAnalyzer.java.in,v 1.2.2.5 2002/05/28 17:34:12 hoenicke Exp $
18  */

19
20 package jode.jvm;
21 import jode.GlobalOptions;
22 import jode.bytecode.BytecodeInfo;
23 import jode.bytecode.ClassInfo;
24 import jode.bytecode.FieldInfo;
25 import jode.bytecode.Handler;
26 import jode.bytecode.Instruction;
27 import jode.bytecode.MethodInfo;
28 import jode.bytecode.Opcodes;
29 import jode.bytecode.Reference;
30 import jode.bytecode.TypeSignature;
31 import jode.type.Type;
32 import jode.type.MethodType;
33
34 import java.lang.reflect.Modifier JavaDoc;
35
36 import java.util.Iterator JavaDoc;
37
38 public class SyntheticAnalyzer implements Opcodes {
39     public final static int UNKNOWN = 0;
40     public final static int GETCLASS = 1;
41     public final static int ACCESSGETFIELD = 2;
42     public final static int ACCESSPUTFIELD = 3;
43     public final static int ACCESSMETHOD = 4;
44     public final static int ACCESSGETSTATIC = 5;
45     public final static int ACCESSPUTSTATIC = 6;
46     public final static int ACCESSSTATICMETHOD = 7;
47     public final static int ACCESSCONSTRUCTOR = 8;
48     public final static int ACCESSDUPPUTFIELD = 9;
49     public final static int ACCESSDUPPUTSTATIC = 10;
50     
51     int kind = UNKNOWN;
52     Reference reference;
53     MethodInfo method;
54     int unifyParam = -1;
55
56     public SyntheticAnalyzer(MethodInfo method, boolean checkName) {
57     this.method = method;
58     if (method.getBytecode() == null)
59         return;
60     if (!checkName || method.getName().equals("class$"))
61         if (checkGetClass())
62         return;
63     if (!checkName || method.getName().startsWith("access$"))
64         if (checkAccess())
65         return;
66     if (method.getName().equals("<init>"))
67         if (checkConstructorAccess())
68         return;
69     }
70
71     public int getKind() {
72     return kind;
73     }
74
75     public Reference getReference() {
76     return reference;
77     }
78
79     /**
80      * Gets the index of the dummy parameter for an ACCESSCONSTRUCTOR.
81      * Normally the 1 but for inner classes it may be 2.
82      */

83     public int getUnifyParam() {
84     return unifyParam;
85     }
86
87     private static final int[] getClassOpcodes = {
88     opc_aload, opc_invokestatic, opc_areturn,
89     opc_astore, opc_new, opc_dup, opc_aload,
90     opc_invokevirtual, opc_invokespecial, opc_athrow
91     };
92     private static final Reference[] getClassRefs = {
93     null, Reference.getReference("Ljava/lang/Class;", "forName",
94                      "(Ljava/lang/String;)Ljava/lang/Class;"),
95     null, null, null, null, null,
96     Reference.getReference("Ljava/lang/Throwable;", "getMessage",
97                    "()Ljava/lang/String;"),
98     Reference.getReference("Ljava/lang/NoClassDefFoundError;", "<init>",
99                    "(Ljava/lang/String;)V"), null
100     };
101
102
103     boolean checkGetClass() {
104     if (!method.isStatic()
105         || !(method.getType()
106          .equals("(Ljava/lang/String;)Ljava/lang/Class;")))
107         return false;
108     
109     BytecodeInfo bytecode = method.getBytecode();
110
111     Handler[] excHandlers = bytecode.getExceptionHandlers();
112     if (excHandlers.length != 1
113         || !"java.lang.ClassNotFoundException".equals(excHandlers[0].type))
114         return false;
115
116     int excSlot = -1;
117     int i = 0;
118     for (Iterator JavaDoc iter = bytecode.getInstructions().iterator(); iter.hasNext(); i++) {
119         Instruction instr = (Instruction) iter.next();
120         while (instr.getOpcode() == opc_nop && iter.hasNext())
121         instr = (Instruction) iter.next();
122         if (i == getClassOpcodes.length
123         || instr.getOpcode() != getClassOpcodes[i])
124         return false;
125         if (i == 0 && (instr.getLocalSlot() != 0
126                || excHandlers[0].start != instr))
127         return false;
128         if (i == 2 && excHandlers[0].end != instr)
129         return false;
130         if (i == 3) {
131         if (excHandlers[0].catcher != instr)
132             return false;
133         excSlot = instr.getLocalSlot();
134         }
135         if (i == 4 && !instr.getClazzType().equals
136         ("Ljava/lang/NoClassDefFoundError;"))
137         return false;
138         if (i == 6 && instr.getLocalSlot() != excSlot)
139         return false;
140         if (getClassRefs[i] != null
141         && !getClassRefs[i].equals(instr.getReference()))
142         return false;
143     }
144     this.kind = GETCLASS;
145     return true;
146     }
147
148     private final int modifierMask = Modifier.PUBLIC | Modifier.STATIC;
149
150     public boolean checkStaticAccess() {
151     ClassInfo clazzInfo = method.getClazzInfo();
152     BytecodeInfo bytecode = method.getBytecode();
153     Iterator JavaDoc iter = bytecode.getInstructions().iterator();
154     boolean dupSeen = false;
155
156     Instruction instr = (Instruction) iter.next();
157     while (instr.getOpcode() == opc_nop && iter.hasNext())
158         instr = (Instruction) iter.next();
159     if (instr.getOpcode() == opc_getstatic) {
160         Reference ref = instr.getReference();
161         ClassInfo refClazz = TypeSignature.getClassInfo(ref.getClazz());
162         if (!refClazz.superClassOf(clazzInfo))
163         return false;
164         FieldInfo refField
165         = refClazz.findField(ref.getName(), ref.getType());
166         if ((refField.getModifiers() & modifierMask) != Modifier.STATIC)
167         return false;
168         instr = (Instruction) iter.next();
169         while (instr.getOpcode() == opc_nop && iter.hasNext())
170         instr = (Instruction) iter.next();
171         if (instr.getOpcode() < opc_ireturn
172         || instr.getOpcode() > opc_areturn)
173         return false;
174         /* For valid bytecode the type matches automatically */
175         reference = ref;
176         kind = ACCESSGETSTATIC;
177         return true;
178     }
179     int params = 0, slot = 0;
180     while (instr.getOpcode() >= opc_iload
181            && instr.getOpcode() <= opc_aload
182            && instr.getLocalSlot() == slot) {
183         params++;
184         slot += (instr.getOpcode() == opc_lload
185              || instr.getOpcode() == opc_dload) ? 2 : 1;
186         instr = (Instruction) iter.next();
187         while (instr.getOpcode() == opc_nop && iter.hasNext())
188         instr = (Instruction) iter.next();
189     }
190     if (instr.getOpcode() == (opc_dup - 3) + 3 * slot) {
191         /* This is probably a opc_dup or opc_dup2,
192          * preceding a opc_putstatic
193          */

194         instr = (Instruction) iter.next();
195         while (instr.getOpcode() == opc_nop && iter.hasNext())
196         instr = (Instruction) iter.next();
197         if (instr.getOpcode() != opc_putstatic)
198         return false;
199         dupSeen = true;
200     }
201     if (instr.getOpcode() == opc_putstatic) {
202         if (params != 1)
203         return false;
204         /* For valid bytecode the type of param matches automatically */
205         Reference ref = instr.getReference();
206         ClassInfo refClazz = TypeSignature.getClassInfo(ref.getClazz());
207         if (!refClazz.superClassOf(clazzInfo))
208         return false;
209         FieldInfo refField
210         = refClazz.findField(ref.getName(), ref.getType());
211         if ((refField.getModifiers() & modifierMask) != Modifier.STATIC)
212         return false;
213         instr = (Instruction) iter.next();
214         while (instr.getOpcode() == opc_nop && iter.hasNext())
215         instr = (Instruction) iter.next();
216         if (dupSeen) {
217         if (instr.getOpcode() < opc_ireturn
218             || instr.getOpcode() > opc_areturn)
219             return false;
220         kind = ACCESSDUPPUTSTATIC;
221         } else {
222         if (instr.getOpcode() != opc_return)
223             return false;
224         kind = ACCESSPUTSTATIC;
225         }
226         reference = ref;
227         return true;
228     }
229     if (instr.getOpcode() == opc_invokestatic) {
230         Reference ref = instr.getReference();
231         ClassInfo refClazz = TypeSignature.getClassInfo(ref.getClazz());
232         if (!refClazz.superClassOf(clazzInfo))
233         return false;
234         MethodInfo refMethod
235         = refClazz.findMethod(ref.getName(), ref.getType());
236         MethodType refType = Type.tMethod(ref.getType());
237         if ((refMethod.getModifiers() & modifierMask) != Modifier.STATIC
238         || refType.getParameterTypes().length != params)
239         return false;
240         instr = (Instruction) iter.next();
241         while (instr.getOpcode() == opc_nop && iter.hasNext())
242         instr = (Instruction) iter.next();
243         if (refType.getReturnType() == Type.tVoid) {
244         if (instr.getOpcode() != opc_return)
245             return false;
246         } else {
247         if (instr.getOpcode() < opc_ireturn
248             || instr.getOpcode() > opc_areturn)
249             return false;
250         }
251
252         /* For valid bytecode the types matches automatically */
253         reference = ref;
254         kind = ACCESSSTATICMETHOD;
255         return true;
256     }
257     return false;
258     }
259
260     public boolean checkAccess() {
261     ClassInfo clazzInfo = method.getClazzInfo();
262     BytecodeInfo bytecode = method.getBytecode();
263     Handler[] excHandlers = bytecode.getExceptionHandlers();
264     boolean dupSeen = false;
265     if (excHandlers != null && excHandlers.length != 0)
266         return false;
267
268     if (method.isStatic()) {
269         if (checkStaticAccess())
270         return true;
271     }
272
273     Iterator JavaDoc iter = bytecode.getInstructions().iterator();
274     Instruction instr = (Instruction) iter.next();
275     while (instr.getOpcode() == opc_nop && iter.hasNext())
276         instr = (Instruction) iter.next();
277     if (instr.getOpcode() != opc_aload || instr.getLocalSlot() != 0)
278         return false;
279     instr = (Instruction) iter.next();
280     while (instr.getOpcode() == opc_nop && iter.hasNext())
281         instr = (Instruction) iter.next();
282
283     if (instr.getOpcode() == opc_getfield) {
284         Reference ref = instr.getReference();
285         ClassInfo refClazz = TypeSignature.getClassInfo(ref.getClazz());
286         if (!refClazz.superClassOf(clazzInfo))
287         return false;
288         FieldInfo refField
289         = refClazz.findField(ref.getName(), ref.getType());
290         if ((refField.getModifiers() & modifierMask) != 0)
291         return false;
292         instr = (Instruction) iter.next();
293         while (instr.getOpcode() == opc_nop && iter.hasNext())
294         instr = (Instruction) iter.next();
295         if (instr.getOpcode() < opc_ireturn
296         || instr.getOpcode() > opc_areturn)
297         return false;
298         /* For valid bytecode the type matches automatically */
299         reference = ref;
300         kind = ACCESSGETFIELD;
301         return true;
302     }
303     int params = 0, slot = 1;
304     while (instr.getOpcode() >= opc_iload
305            && instr.getOpcode() <= opc_aload
306            && instr.getLocalSlot() == slot) {
307         params++;
308         slot += (instr.getOpcode() == opc_lload
309              || instr.getOpcode() == opc_dload) ? 2 : 1;
310         instr = (Instruction) iter.next();
311         while (instr.getOpcode() == opc_nop && iter.hasNext())
312         instr = (Instruction) iter.next();
313     }
314     if (instr.getOpcode() == (opc_dup_x1 - 6) + 3 * slot) {
315         /* This is probably a opc_dup_x1 or opc_dup2_x1,
316          * preceding a opc_putfield
317          */

318         instr = (Instruction) iter.next();
319         while (instr.getOpcode() == opc_nop && iter.hasNext())
320         instr = (Instruction) iter.next();
321         if (instr.getOpcode() != opc_putfield)
322         return false;
323         dupSeen = true;
324     }
325     if (instr.getOpcode() == opc_putfield) {
326         if (params != 1)
327         return false;
328         /* For valid bytecode the type of param matches automatically */
329         Reference ref = instr.getReference();
330         ClassInfo refClazz = TypeSignature.getClassInfo(ref.getClazz());
331         if (!refClazz.superClassOf(clazzInfo))
332         return false;
333         FieldInfo refField
334         = refClazz.findField(ref.getName(), ref.getType());
335         if ((refField.getModifiers() & modifierMask) != 0)
336         return false;
337
338         instr = (Instruction) iter.next();
339         while (instr.getOpcode() == opc_nop && iter.hasNext())
340         instr = (Instruction) iter.next();
341         if (dupSeen) {
342         if (instr.getOpcode() < opc_ireturn
343             || instr.getOpcode() > opc_areturn)
344             return false;
345         kind = ACCESSDUPPUTFIELD;
346         } else {
347         if (instr.getOpcode() != opc_return)
348             return false;
349         kind = ACCESSPUTFIELD;
350         }
351         reference = ref;
352         return true;
353     }
354     if (instr.getOpcode() == opc_invokespecial) {
355         Reference ref = instr.getReference();
356         ClassInfo refClazz = TypeSignature.getClassInfo(ref.getClazz());
357         if (!refClazz.superClassOf(clazzInfo))
358         return false;
359         MethodInfo refMethod
360         = refClazz.findMethod(ref.getName(), ref.getType());
361         MethodType refType = Type.tMethod(ref.getType());
362         if ((refMethod.getModifiers() & modifierMask) != 0
363         || refType.getParameterTypes().length != params)
364         return false;
365         instr = (Instruction) iter.next();
366         while (instr.getOpcode() == opc_nop && iter.hasNext())
367         instr = (Instruction) iter.next();
368         if (refType.getReturnType() == Type.tVoid) {
369         if (instr.getOpcode() != opc_return)
370             return false;
371         } else {
372         if (instr.getOpcode() < opc_ireturn
373             || instr.getOpcode() > opc_areturn)
374             return false;
375         }
376
377         /* For valid bytecode the types matches automatically */
378         reference = ref;
379         kind = ACCESSMETHOD;
380         return true;
381     }
382     return false;
383     }
384
385     public boolean checkConstructorAccess() {
386     ClassInfo clazzInfo = method.getClazzInfo();
387     BytecodeInfo bytecode = method.getBytecode();
388     String JavaDoc[] paramTypes
389         = TypeSignature.getParameterTypes(method.getType());
390     Handler[] excHandlers = bytecode.getExceptionHandlers();
391     if (excHandlers != null && excHandlers.length != 0)
392         return false;
393     Iterator JavaDoc iter = bytecode.getInstructions().iterator();
394
395     Instruction instr = (Instruction) iter.next();
396     while (instr.getOpcode() == opc_nop && iter.hasNext())
397         instr = (Instruction) iter.next();
398     int params = 0, slot = 0;
399     while (instr.getOpcode() >= opc_iload
400            && instr.getOpcode() <= opc_aload) {
401
402         if (instr.getLocalSlot() > slot
403         && unifyParam == -1 && params > 0
404         && paramTypes[params - 1].charAt(0) == 'L') {
405         unifyParam = params;
406         params++;
407         slot++;
408         }
409         if (instr.getLocalSlot() != slot)
410         return false;
411         
412         params++;
413         slot += (instr.getOpcode() == opc_lload
414              || instr.getOpcode() == opc_dload) ? 2 : 1;
415         instr = (Instruction) iter.next();
416     }
417     if (params > 0 && instr.getOpcode() == opc_invokespecial) {
418
419         if (unifyParam == -1 && params <= paramTypes.length
420         && paramTypes[params - 1].charAt(0) == 'L')
421         unifyParam = params++;
422
423         Reference ref = instr.getReference();
424         ClassInfo refClazz = TypeSignature.getClassInfo(ref.getClazz());
425         if (refClazz != clazzInfo)
426         return false;
427         MethodInfo refMethod
428         = refClazz.findMethod(ref.getName(), ref.getType());
429         MethodType refType = Type.tMethod(ref.getType());
430         if ((refMethod.getModifiers() & modifierMask) != 0
431         || !refMethod.getName().equals("<init>")
432         || unifyParam == -1
433         || refType.getParameterTypes().length != params - 2)
434         return false;
435     
436         instr = (Instruction) iter.next();
437         if (instr.getOpcode() != opc_return)
438         return false;
439
440         /* We don't check if types matches. No problem since we only
441          * need to make sure, this constructor doesn't do anything
442          * more than relay to the real one.
443          */

444         reference = ref;
445         kind = ACCESSCONSTRUCTOR;
446         return true;
447     }
448     return false;
449     }
450 }
451
452
Popular Tags