001: /* SyntheticAnalyzer Copyright (C) 1999-2002 Jochen Hoenicke.
002: *
003: * This program is free software; you can redistribute it and/or modify
004: * it under the terms of the GNU Lesser General Public License as published by
005: * the Free Software Foundation; either version 2, or (at your option)
006: * any later version.
007: *
008: * This program is distributed in the hope that it will be useful,
009: * but WITHOUT ANY WARRANTY; without even the implied warranty of
010: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
011: * GNU General Public License for more details.
012: *
013: * You should have received a copy of the GNU Lesser General Public License
014: * along with this program; see the file COPYING.LESSER. If not, write to
015: * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
016: *
017: * $Id: SyntheticAnalyzer.java.in,v 1.2.2.5 2002/05/28 17:34:12 hoenicke Exp $
018: */
019:
020: package jode.jvm;
021:
022: import jode.GlobalOptions;
023: import jode.bytecode.BytecodeInfo;
024: import jode.bytecode.ClassInfo;
025: import jode.bytecode.FieldInfo;
026: import jode.bytecode.Handler;
027: import jode.bytecode.Instruction;
028: import jode.bytecode.MethodInfo;
029: import jode.bytecode.Opcodes;
030: import jode.bytecode.Reference;
031: import jode.bytecode.TypeSignature;
032: import jode.type.Type;
033: import jode.type.MethodType;
034:
035: import java.lang.reflect.Modifier;
036:
037: import java.util.Iterator;
038:
039: public class SyntheticAnalyzer implements Opcodes {
040: public final static int UNKNOWN = 0;
041: public final static int GETCLASS = 1;
042: public final static int ACCESSGETFIELD = 2;
043: public final static int ACCESSPUTFIELD = 3;
044: public final static int ACCESSMETHOD = 4;
045: public final static int ACCESSGETSTATIC = 5;
046: public final static int ACCESSPUTSTATIC = 6;
047: public final static int ACCESSSTATICMETHOD = 7;
048: public final static int ACCESSCONSTRUCTOR = 8;
049: public final static int ACCESSDUPPUTFIELD = 9;
050: public final static int ACCESSDUPPUTSTATIC = 10;
051:
052: int kind = UNKNOWN;
053: Reference reference;
054: MethodInfo method;
055: int unifyParam = -1;
056:
057: public SyntheticAnalyzer(MethodInfo method, boolean checkName) {
058: this .method = method;
059: if (method.getBytecode() == null)
060: return;
061: if (!checkName || method.getName().equals("class$"))
062: if (checkGetClass())
063: return;
064: if (!checkName || method.getName().startsWith("access$"))
065: if (checkAccess())
066: return;
067: if (method.getName().equals("<init>"))
068: if (checkConstructorAccess())
069: return;
070: }
071:
072: public int getKind() {
073: return kind;
074: }
075:
076: public Reference getReference() {
077: return reference;
078: }
079:
080: /**
081: * Gets the index of the dummy parameter for an ACCESSCONSTRUCTOR.
082: * Normally the 1 but for inner classes it may be 2.
083: */
084: public int getUnifyParam() {
085: return unifyParam;
086: }
087:
088: private static final int[] getClassOpcodes = { opc_aload,
089: opc_invokestatic, opc_areturn, opc_astore, opc_new,
090: opc_dup, opc_aload, opc_invokevirtual, opc_invokespecial,
091: opc_athrow };
092: private static final Reference[] getClassRefs = {
093: null,
094: Reference.getReference("Ljava/lang/Class;", "forName",
095: "(Ljava/lang/String;)Ljava/lang/Class;"),
096: null,
097: null,
098: null,
099: null,
100: null,
101: Reference.getReference("Ljava/lang/Throwable;",
102: "getMessage", "()Ljava/lang/String;"),
103: Reference.getReference("Ljava/lang/NoClassDefFoundError;",
104: "<init>", "(Ljava/lang/String;)V"), null };
105:
106: boolean checkGetClass() {
107: if (!method.isStatic()
108: || !(method.getType()
109: .equals("(Ljava/lang/String;)Ljava/lang/Class;")))
110: return false;
111:
112: BytecodeInfo bytecode = method.getBytecode();
113:
114: Handler[] excHandlers = bytecode.getExceptionHandlers();
115: if (excHandlers.length != 1
116: || !"java.lang.ClassNotFoundException"
117: .equals(excHandlers[0].type))
118: return false;
119:
120: int excSlot = -1;
121: int i = 0;
122: for (Iterator iter = bytecode.getInstructions().iterator(); iter
123: .hasNext(); i++) {
124: Instruction instr = (Instruction) iter.next();
125: while (instr.getOpcode() == opc_nop && iter.hasNext())
126: instr = (Instruction) iter.next();
127: if (i == getClassOpcodes.length
128: || instr.getOpcode() != getClassOpcodes[i])
129: return false;
130: if (i == 0
131: && (instr.getLocalSlot() != 0 || excHandlers[0].start != instr))
132: return false;
133: if (i == 2 && excHandlers[0].end != instr)
134: return false;
135: if (i == 3) {
136: if (excHandlers[0].catcher != instr)
137: return false;
138: excSlot = instr.getLocalSlot();
139: }
140: if (i == 4
141: && !instr.getClazzType().equals(
142: "Ljava/lang/NoClassDefFoundError;"))
143: return false;
144: if (i == 6 && instr.getLocalSlot() != excSlot)
145: return false;
146: if (getClassRefs[i] != null
147: && !getClassRefs[i].equals(instr.getReference()))
148: return false;
149: }
150: this .kind = GETCLASS;
151: return true;
152: }
153:
154: private final int modifierMask = Modifier.PUBLIC | Modifier.STATIC;
155:
156: public boolean checkStaticAccess() {
157: ClassInfo clazzInfo = method.getClazzInfo();
158: BytecodeInfo bytecode = method.getBytecode();
159: Iterator iter = bytecode.getInstructions().iterator();
160: boolean dupSeen = false;
161:
162: Instruction instr = (Instruction) iter.next();
163: while (instr.getOpcode() == opc_nop && iter.hasNext())
164: instr = (Instruction) iter.next();
165: if (instr.getOpcode() == opc_getstatic) {
166: Reference ref = instr.getReference();
167: ClassInfo refClazz = TypeSignature.getClassInfo(ref
168: .getClazz());
169: if (!refClazz.super ClassOf(clazzInfo))
170: return false;
171: FieldInfo refField = refClazz.findField(ref.getName(), ref
172: .getType());
173: if ((refField.getModifiers() & modifierMask) != Modifier.STATIC)
174: return false;
175: instr = (Instruction) iter.next();
176: while (instr.getOpcode() == opc_nop && iter.hasNext())
177: instr = (Instruction) iter.next();
178: if (instr.getOpcode() < opc_ireturn
179: || instr.getOpcode() > opc_areturn)
180: return false;
181: /* For valid bytecode the type matches automatically */
182: reference = ref;
183: kind = ACCESSGETSTATIC;
184: return true;
185: }
186: int params = 0, slot = 0;
187: while (instr.getOpcode() >= opc_iload
188: && instr.getOpcode() <= opc_aload
189: && instr.getLocalSlot() == slot) {
190: params++;
191: slot += (instr.getOpcode() == opc_lload || instr
192: .getOpcode() == opc_dload) ? 2 : 1;
193: instr = (Instruction) iter.next();
194: while (instr.getOpcode() == opc_nop && iter.hasNext())
195: instr = (Instruction) iter.next();
196: }
197: if (instr.getOpcode() == (opc_dup - 3) + 3 * slot) {
198: /* This is probably a opc_dup or opc_dup2,
199: * preceding a opc_putstatic
200: */
201: instr = (Instruction) iter.next();
202: while (instr.getOpcode() == opc_nop && iter.hasNext())
203: instr = (Instruction) iter.next();
204: if (instr.getOpcode() != opc_putstatic)
205: return false;
206: dupSeen = true;
207: }
208: if (instr.getOpcode() == opc_putstatic) {
209: if (params != 1)
210: return false;
211: /* For valid bytecode the type of param matches automatically */
212: Reference ref = instr.getReference();
213: ClassInfo refClazz = TypeSignature.getClassInfo(ref
214: .getClazz());
215: if (!refClazz.super ClassOf(clazzInfo))
216: return false;
217: FieldInfo refField = refClazz.findField(ref.getName(), ref
218: .getType());
219: if ((refField.getModifiers() & modifierMask) != Modifier.STATIC)
220: return false;
221: instr = (Instruction) iter.next();
222: while (instr.getOpcode() == opc_nop && iter.hasNext())
223: instr = (Instruction) iter.next();
224: if (dupSeen) {
225: if (instr.getOpcode() < opc_ireturn
226: || instr.getOpcode() > opc_areturn)
227: return false;
228: kind = ACCESSDUPPUTSTATIC;
229: } else {
230: if (instr.getOpcode() != opc_return)
231: return false;
232: kind = ACCESSPUTSTATIC;
233: }
234: reference = ref;
235: return true;
236: }
237: if (instr.getOpcode() == opc_invokestatic) {
238: Reference ref = instr.getReference();
239: ClassInfo refClazz = TypeSignature.getClassInfo(ref
240: .getClazz());
241: if (!refClazz.super ClassOf(clazzInfo))
242: return false;
243: MethodInfo refMethod = refClazz.findMethod(ref.getName(),
244: ref.getType());
245: MethodType refType = Type.tMethod(ref.getType());
246: if ((refMethod.getModifiers() & modifierMask) != Modifier.STATIC
247: || refType.getParameterTypes().length != params)
248: return false;
249: instr = (Instruction) iter.next();
250: while (instr.getOpcode() == opc_nop && iter.hasNext())
251: instr = (Instruction) iter.next();
252: if (refType.getReturnType() == Type.tVoid) {
253: if (instr.getOpcode() != opc_return)
254: return false;
255: } else {
256: if (instr.getOpcode() < opc_ireturn
257: || instr.getOpcode() > opc_areturn)
258: return false;
259: }
260:
261: /* For valid bytecode the types matches automatically */
262: reference = ref;
263: kind = ACCESSSTATICMETHOD;
264: return true;
265: }
266: return false;
267: }
268:
269: public boolean checkAccess() {
270: ClassInfo clazzInfo = method.getClazzInfo();
271: BytecodeInfo bytecode = method.getBytecode();
272: Handler[] excHandlers = bytecode.getExceptionHandlers();
273: boolean dupSeen = false;
274: if (excHandlers != null && excHandlers.length != 0)
275: return false;
276:
277: if (method.isStatic()) {
278: if (checkStaticAccess())
279: return true;
280: }
281:
282: Iterator iter = bytecode.getInstructions().iterator();
283: Instruction instr = (Instruction) iter.next();
284: while (instr.getOpcode() == opc_nop && iter.hasNext())
285: instr = (Instruction) iter.next();
286: if (instr.getOpcode() != opc_aload || instr.getLocalSlot() != 0)
287: return false;
288: instr = (Instruction) iter.next();
289: while (instr.getOpcode() == opc_nop && iter.hasNext())
290: instr = (Instruction) iter.next();
291:
292: if (instr.getOpcode() == opc_getfield) {
293: Reference ref = instr.getReference();
294: ClassInfo refClazz = TypeSignature.getClassInfo(ref
295: .getClazz());
296: if (!refClazz.super ClassOf(clazzInfo))
297: return false;
298: FieldInfo refField = refClazz.findField(ref.getName(), ref
299: .getType());
300: if ((refField.getModifiers() & modifierMask) != 0)
301: return false;
302: instr = (Instruction) iter.next();
303: while (instr.getOpcode() == opc_nop && iter.hasNext())
304: instr = (Instruction) iter.next();
305: if (instr.getOpcode() < opc_ireturn
306: || instr.getOpcode() > opc_areturn)
307: return false;
308: /* For valid bytecode the type matches automatically */
309: reference = ref;
310: kind = ACCESSGETFIELD;
311: return true;
312: }
313: int params = 0, slot = 1;
314: while (instr.getOpcode() >= opc_iload
315: && instr.getOpcode() <= opc_aload
316: && instr.getLocalSlot() == slot) {
317: params++;
318: slot += (instr.getOpcode() == opc_lload || instr
319: .getOpcode() == opc_dload) ? 2 : 1;
320: instr = (Instruction) iter.next();
321: while (instr.getOpcode() == opc_nop && iter.hasNext())
322: instr = (Instruction) iter.next();
323: }
324: if (instr.getOpcode() == (opc_dup_x1 - 6) + 3 * slot) {
325: /* This is probably a opc_dup_x1 or opc_dup2_x1,
326: * preceding a opc_putfield
327: */
328: instr = (Instruction) iter.next();
329: while (instr.getOpcode() == opc_nop && iter.hasNext())
330: instr = (Instruction) iter.next();
331: if (instr.getOpcode() != opc_putfield)
332: return false;
333: dupSeen = true;
334: }
335: if (instr.getOpcode() == opc_putfield) {
336: if (params != 1)
337: return false;
338: /* For valid bytecode the type of param matches automatically */
339: Reference ref = instr.getReference();
340: ClassInfo refClazz = TypeSignature.getClassInfo(ref
341: .getClazz());
342: if (!refClazz.super ClassOf(clazzInfo))
343: return false;
344: FieldInfo refField = refClazz.findField(ref.getName(), ref
345: .getType());
346: if ((refField.getModifiers() & modifierMask) != 0)
347: return false;
348:
349: instr = (Instruction) iter.next();
350: while (instr.getOpcode() == opc_nop && iter.hasNext())
351: instr = (Instruction) iter.next();
352: if (dupSeen) {
353: if (instr.getOpcode() < opc_ireturn
354: || instr.getOpcode() > opc_areturn)
355: return false;
356: kind = ACCESSDUPPUTFIELD;
357: } else {
358: if (instr.getOpcode() != opc_return)
359: return false;
360: kind = ACCESSPUTFIELD;
361: }
362: reference = ref;
363: return true;
364: }
365: if (instr.getOpcode() == opc_invokespecial) {
366: Reference ref = instr.getReference();
367: ClassInfo refClazz = TypeSignature.getClassInfo(ref
368: .getClazz());
369: if (!refClazz.super ClassOf(clazzInfo))
370: return false;
371: MethodInfo refMethod = refClazz.findMethod(ref.getName(),
372: ref.getType());
373: MethodType refType = Type.tMethod(ref.getType());
374: if ((refMethod.getModifiers() & modifierMask) != 0
375: || refType.getParameterTypes().length != params)
376: return false;
377: instr = (Instruction) iter.next();
378: while (instr.getOpcode() == opc_nop && iter.hasNext())
379: instr = (Instruction) iter.next();
380: if (refType.getReturnType() == Type.tVoid) {
381: if (instr.getOpcode() != opc_return)
382: return false;
383: } else {
384: if (instr.getOpcode() < opc_ireturn
385: || instr.getOpcode() > opc_areturn)
386: return false;
387: }
388:
389: /* For valid bytecode the types matches automatically */
390: reference = ref;
391: kind = ACCESSMETHOD;
392: return true;
393: }
394: return false;
395: }
396:
397: public boolean checkConstructorAccess() {
398: ClassInfo clazzInfo = method.getClazzInfo();
399: BytecodeInfo bytecode = method.getBytecode();
400: String[] paramTypes = TypeSignature.getParameterTypes(method
401: .getType());
402: Handler[] excHandlers = bytecode.getExceptionHandlers();
403: if (excHandlers != null && excHandlers.length != 0)
404: return false;
405: Iterator iter = bytecode.getInstructions().iterator();
406:
407: Instruction instr = (Instruction) iter.next();
408: while (instr.getOpcode() == opc_nop && iter.hasNext())
409: instr = (Instruction) iter.next();
410: int params = 0, slot = 0;
411: while (instr.getOpcode() >= opc_iload
412: && instr.getOpcode() <= opc_aload) {
413:
414: if (instr.getLocalSlot() > slot && unifyParam == -1
415: && params > 0
416: && paramTypes[params - 1].charAt(0) == 'L') {
417: unifyParam = params;
418: params++;
419: slot++;
420: }
421: if (instr.getLocalSlot() != slot)
422: return false;
423:
424: params++;
425: slot += (instr.getOpcode() == opc_lload || instr
426: .getOpcode() == opc_dload) ? 2 : 1;
427: instr = (Instruction) iter.next();
428: }
429: if (params > 0 && instr.getOpcode() == opc_invokespecial) {
430:
431: if (unifyParam == -1 && params <= paramTypes.length
432: && paramTypes[params - 1].charAt(0) == 'L')
433: unifyParam = params++;
434:
435: Reference ref = instr.getReference();
436: ClassInfo refClazz = TypeSignature.getClassInfo(ref
437: .getClazz());
438: if (refClazz != clazzInfo)
439: return false;
440: MethodInfo refMethod = refClazz.findMethod(ref.getName(),
441: ref.getType());
442: MethodType refType = Type.tMethod(ref.getType());
443: if ((refMethod.getModifiers() & modifierMask) != 0
444: || !refMethod.getName().equals("<init>")
445: || unifyParam == -1
446: || refType.getParameterTypes().length != params - 2)
447: return false;
448:
449: instr = (Instruction) iter.next();
450: if (instr.getOpcode() != opc_return)
451: return false;
452:
453: /* We don't check if types matches. No problem since we only
454: * need to make sure, this constructor doesn't do anything
455: * more than relay to the real one.
456: */
457: reference = ref;
458: kind = ACCESSCONSTRUCTOR;
459: return true;
460: }
461: return false;
462: }
463: }
|