001: /*
002: * @(#)ClassEntry.java 1.27 06/10/10
003: *
004: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: *
026: */
027:
028: package dependenceAnalyzer;
029:
030: import util.*;
031: import java.util.*;
032: import components.*;
033: import consts.Const;
034:
035: /*
036: * Class ClassEntry is for use with Member-level dependence analysis.
037: * It is not only a part of the dependence relations but also
038: * a container for MemberDependenceNodes, and thus
039: * a part of the naming mechanism.
040: *
041: * This is where class members are parsed, and thus
042: * their dependences discovered and exposed.
043: */
044:
045: public class ClassEntry extends DependenceNode implements
046: MemberArcTypes {
047: /*
048: * public parts.
049: */
050: public boolean signatureFlag = false;
051:
052: public ClassEntry super Class() {
053: return super ClassEntry;
054: }
055:
056: public Enumeration subclasses() {
057: return (subclassSet == null) ? EmptyEnumeration.instance
058: : subclassSet.elements();
059: }
060:
061: public Enumeration members() {
062: return (memberSet == null) ? EmptyEnumeration.instance
063: : memberSet.elements();
064: }
065:
066: public Enumeration interfaces() {
067: return (interfaceSet == null) ? EmptyEnumeration.instance
068: : interfaceSet.elements();
069: }
070:
071: public MemberDependenceNode lookupMember(MemberName mn) {
072: if (memberSet == null)
073: return null;
074: return (MemberDependenceNode) (memberSet.get(mn));
075: }
076:
077: private MemberName t = new MemberName(this , "");
078:
079: public MemberDependenceNode lookupMember(String mname) {
080: // ... won't work multithreaded!...
081: t.name = mname.intern();
082: return lookupMember(t);
083: }
084:
085: public MemberDependenceNode lookupAddMember(MemberName mn,
086: int mflags) {
087: MemberDependenceNode mnode = lookupMember(mn);
088: if (mnode == null) {
089: mnode = new MemberDependenceNode(mn, mflags);
090: if (memberSet == null)
091: memberSet = new Hashtable();
092: memberSet.put(mn, mnode);
093: } else if (mflags != 0) {
094: mnode.flags = mflags;
095: }
096: if ((this .flags & EXCLUDED) != 0) {
097: // class is excluded, and so are all members.
098: mnode.flags |= MemberDependenceNode.EXCLUDED;
099: }
100:
101: return mnode;
102: }
103:
104: public ClassEntry(String name) {
105: super (name);
106: className = name;
107: nodeState = UNANALYZED;
108: }
109:
110: public boolean analyzeClass(ClassDictionary cd, boolean f) {
111: signatureFlag = f;
112: return (analyzeClass(cd));
113: }
114:
115: public boolean analyzeClass(ClassDictionary cd) {
116: if (nodeState != UNANALYZED)
117: return (nodeState != ERROR); // already done.
118: nodeState = ANALYZED; // do this early to prevent excess recursion
119: cdict = cd; // share the dictionary with the rest of the code.
120:
121: ClassInfo ci = cdict.findClassInfo(className);
122: if (ci == null) {
123: // cannot find class info to analyze.
124: // this is not good.
125: nodeState = ERROR;
126: } else {
127: nodeState = parseClassInfo(ci);
128: }
129: return (nodeState != ERROR);
130: }
131:
132: /*
133: * A class which is marked as an interface does not have to be
134: * a Java TM Interface. It merely has to define a contract between
135: * two software subsystems. java.applet.Applet is a good example of
136: * an interface.
137: * An interface is always EXCLUDED.
138: * An interface has additional, imputed, members, which
139: * are inhereted from superclasses and interfaces, and which
140: * form part of the contract. makeInterface creates these after
141: * inspecting all superclasses and Java interfaces. This is so that
142: * our override-based dependence analysis works.
143: * makeInterface returns true on success, false on any adversary
144: * Adversary includes:
145: * inability to find class file
146: * class is not EXCLUDED
147: * inability to find superclasses or interfaces
148: */
149: public boolean makeInterface(ClassDictionary cd) {
150: cdict = cd;
151: if (nodeState == UNANALYZED)
152: analyzeClass(cd);
153: if (nodeState == ERROR)
154: return false;
155: if ((flags & EXCLUDED) == 0)
156: return false;
157: if ((flags & DEFINES_INTERFACE) != 0)
158: return true; // done!
159: if (!imputeMembers(super ClassEntry))
160: return false;
161: if (interfaceSet != null) {
162: Enumeration ilist = interfaceSet.elements();
163: while (ilist.hasMoreElements()) {
164: if (!imputeMembers((ClassEntry) (ilist.nextElement())))
165: return false;
166: }
167: }
168: flags |= DEFINES_INTERFACE;
169: return true;
170: }
171:
172: /*
173: * Flags. This is pretty much up to the user, except for this one
174: * which will govern how things work.
175: */
176: public static final int EXCLUDED = MemberDependenceNode.EXCLUDED;
177: public static final int DEFINES_INTERFACE = 2;
178: public static final int HAS_OVERRIDING = 4;
179:
180: /*
181: * Implementation parts.
182: */
183: private String className;
184: private ClassEntry super ClassEntry;
185: private Vector subclassSet;
186: private Dictionary memberSet;
187: private Vector interfaceSet = new Vector();
188:
189: //
190: // I feel rather silly having this here, as there is
191: // no requirement that a ClassEntry be associated with only
192: // one dictionary. But the fact is, this variable is
193: // referenced in many many places in the analysis routines,
194: // and I'd otherwise have to keep passing it around...
195: private ClassDictionary cdict;
196:
197: private int parseClassInfo(ClassInfo ci) {
198: //
199: // This class cannot be understood without
200: // first understanding its super class
201: //
202: int resultState = ANALYZED;
203:
204: if (ci.super Class != null) {
205: ClassEntry sup = cdict.lookupAdd(ci.super Class.name.string);
206: if (sup.nodeState == UNANALYZED)
207: sup.analyzeClass(cdict); // recurse.
208: if (sup.nodeState != ERROR) {
209: super ClassEntry = sup;
210: sup.addSubclass(this );
211: }
212: }
213:
214: // interfaces, if any.
215: if (ci.interfaces != null) {
216: for (int i = 0; i < ci.interfaces.length; i++) {
217: ClassEntry sup = cdict
218: .lookupAdd(ci.interfaces[i].name.string);
219: interfaceSet.addElement(sup);
220: sup.addSubclass(this );
221: if (sup.nodeState == UNANALYZED)
222: sup.analyzeClass(cdict); // recurse.
223: }
224: }
225:
226: // Take Care the Inner class as well.
227: if (ci.classAttributes != null) {
228: for (int i = 0; i < ci.classAttributes.length; i++) {
229: if (ci.classAttributes[i].name.string
230: .equals("InnerClasses")) {
231: for (int j = 0; j < ci.innerClassAttr
232: .getInnerClassCount(); j++) {
233: String name = ci.innerClassAttr.getFullName(j);
234: if (name.equals("ICA-ReferingToSelf"))
235: continue;
236:
237: ClassEntry inner = cdict.lookupAdd(name);
238: if (inner.nodeState == UNANALYZED)
239: // if -signatureFlag is set, get api dependency as well.
240: inner.analyzeClass(cdict, signatureFlag); // recurse.
241: }
242: }
243: }
244: }
245:
246: MemberDependenceNode mnode;
247:
248: // all the methods.
249: if (ci.methods != null) {
250: for (int i = 0; i < ci.methods.length; i++) {
251: mnode = overrideAnalysis(parseMethodInfo(ci.methods[i]));
252: if (mnode == null) {
253: resultState = ERROR; // bad news.
254: } else {
255: mnode.nodeState = DependenceNode.ANALYZED;
256: }
257: }
258: }
259:
260: // and the fields.
261: if (ci.fields != null) {
262: for (int i = 0; i < ci.fields.length; i++) {
263: mnode = parseFieldInfo(ci.fields[i]);
264: if (mnode == null) {
265: resultState = ERROR; // bad news.
266: } else {
267: mnode.nodeState = DependenceNode.ANALYZED;
268: }
269: }
270: }
271:
272: return resultState;
273: }
274:
275: private MemberDependenceNode overrideAnalysis(
276: MemberDependenceNode mn) {
277: if (mn == null)
278: return null; // must have been some error
279: if ((mn.flags & MemberDependenceNode.NO_OVERRIDING) != 0)
280: return mn; // these don't override.
281: MemberName nm = (MemberName) ((MemberName) (mn.name())).clone(); // make a dirty copy.
282: int anyOverriding = 0;
283: if (super ClassEntry != null)
284: anyOverriding += super ClassEntry.overrideCheckUp(mn, nm);
285: Enumeration ife = interfaceSet.elements();
286: while (ife.hasMoreElements()) {
287: ClassEntry iface = (ClassEntry) (ife.nextElement());
288: anyOverriding += iface.overrideCheckUp(mn, nm);
289: }
290: if (anyOverriding != 0) {
291: this .flags |= HAS_OVERRIDING;
292: }
293: return mn;
294: }
295:
296: private int overrideCheckUp(MemberDependenceNode mn,
297: MemberName nameCopy) {
298:
299: if (this .nodeState != ANALYZED)
300: return 0; // error or unanalyzed interface
301:
302: int nOverrides = 0;
303:
304: nameCopy.classEntry = this ;
305: MemberDependenceNode target = lookupMember(nameCopy);
306: if (target != null) {
307: // have a case of overriding.
308: // various sets may not exist yet, so be careful.
309: if (target.memberOverriddenBy == null) {
310: target.memberOverriddenBy = new util.Set();
311: }
312: target.memberOverriddenBy.addElement(mn);
313: target.flags |= MemberDependenceNode.OVERRIDDEN;
314: if (mn.memberOverrides == null) {
315: mn.memberOverrides = new util.Set();
316: }
317: mn.memberOverrides.addElement(target);
318: nOverrides += 1;
319: }
320: if (super ClassEntry != null)
321: nOverrides += super ClassEntry.overrideCheckUp(mn, nameCopy);
322: Enumeration ife = interfaceSet.elements();
323: while (ife.hasMoreElements()) {
324: ClassEntry iface = (ClassEntry) (ife.nextElement());
325: nOverrides += iface.overrideCheckUp(mn, nameCopy);
326: }
327:
328: return nOverrides;
329: }
330:
331: private static int getUnsignedShort(byte code[], int w) {
332: return (((int) code[w] & 0xff) << 8)
333: | ((int) code[w + 1] & 0xff);
334: }
335:
336: private ClassEntry conditionalClassReference(
337: MemberDependenceNode referring, ClassConstant ref,
338: int referenceType) {
339: String classname = ref.name.string;
340: if (className.equals(classname)) {
341: return this ;
342: }
343: ClassEntry cer = cdict.lookupAdd(classname);
344: DependenceArc de = new DependenceArc(referring, cer,
345: referenceType);
346: referring.nodeDependsOn.addElement(de);
347: cer.nodeDependedOn.addElement(de);
348: return cer;
349: }
350:
351: private void addCrossReference(MemberDependenceNode referring,
352: FMIrefConstant fref, int arctype) {
353: ClassEntry targetClass = conditionalClassReference(referring,
354: fref.clas, ARC_CLASS);
355: String refname;
356: if (arctype == ARC_CALLS) {
357: // for methods, name includes signature.
358: refname = fref.sig.name.string + fref.sig.type.string;
359: } else {
360: // for data, name is just name.
361: refname = fref.sig.name.string;
362: }
363: MemberDependenceNode targetNode = targetClass.lookupAddMember(
364: new MemberName(targetClass, refname), 0);
365: DependenceArc de = new DependenceArc(referring, targetNode,
366: arctype);
367: referring.nodeDependsOn.addElement(de);
368: targetNode.nodeDependedOn.addElement(de);
369: }
370:
371: private ClassEntry javaLangString;
372: private MemberDependenceNode stringInit;
373:
374: private void makeString(MemberDependenceNode referring) {
375: if (javaLangString == null) {
376: javaLangString = cdict.lookupAdd("java/lang/String");
377: stringInit = javaLangString.lookupAddMember(new MemberName(
378: javaLangString, "<init>([C)V"), 0);
379: }
380: DependenceArc da = new DependenceArc(referring, stringInit,
381: ARC_CALLS);
382: referring.nodeDependsOn.addElement(da);
383: stringInit.nodeDependedOn.addElement(da);
384: }
385:
386: private void doSignatureDepend(String str,
387: MemberDependenceNode referring) {
388: ParamSignatureParser csi;
389:
390: csi = new ParamSignatureParser(str, referring);
391: try {
392: csi.iterate();
393: } catch (util.DataFormatException e) {
394: e.printStackTrace();
395: }
396: }
397:
398: private MemberDependenceNode parseMethodInfo(MethodInfo mi) {
399:
400: MemberDependenceNode md = parseClassMemberInfo(mi,
401: MemberDependenceNode.METHOD);
402:
403: if ((md.flags & MemberDependenceNode.EXCLUDED) != 0) {
404: return md; // we have all we need.
405: }
406:
407: /* Should set an option -listSignatureDepend to turn this on. how?? */
408: if (signatureFlag)
409: doSignatureDepend(mi.type.string, md);
410:
411: if (mi.exceptionTable != null) {
412: for (int j = 0; j < mi.exceptionTable.length; j++) {
413: ExceptionEntry ee = mi.exceptionTable[j];
414: if (ee.catchType != null)
415: conditionalClassReference(md, ee.catchType,
416: ARC_EXCEPTION);
417: }
418: }
419: if (mi.exceptionsThrown != null) {
420: for (int j = 0; j < mi.exceptionsThrown.length; j++) {
421: conditionalClassReference(md, mi.exceptionsThrown[j],
422: ARC_EXCEPTION);
423: }
424: }
425: doCode: if (mi.code != null) {
426: byte code[] = mi.code;
427: try {
428: int locs[] = mi.getLdcInstructions();
429: ConstantObject cpool[] = mi.parent.getConstantPool()
430: .getConstants();
431:
432: for (int j = 0; j < locs.length; j++) {
433: ConstantObject o = cpool[(int) code[locs[j] + 1] & 0xff];
434: if (o instanceof StringConstant) {
435: makeString(md);
436: } else if (o instanceof ClassConstant) {
437: conditionalClassReference(md,
438: (ClassConstant) o, ARC_CLASS);
439: }
440: }
441: locs = mi.getWideConstantRefInstructions();
442: for (int j = 0; j < locs.length; j++) {
443: FMIrefConstant fref;
444:
445: switch ((int) code[locs[j]] & 0xff) {
446: case Const.opc_anewarray:
447: case Const.opc_checkcast:
448: case Const.opc_multianewarray:
449: case Const.opc_new:
450: case Const.opc_instanceof : {
451: conditionalClassReference(md,
452: (ClassConstant) cpool[getUnsignedShort(
453: code, locs[j] + 1)], ARC_CLASS);
454: break;
455: }
456: case Const.opc_getfield:
457: case Const.opc_getstatic:
458: fref = (FMIrefConstant) cpool[getUnsignedShort(
459: code, locs[j] + 1)];
460: addCrossReference(md, fref, ARC_READS);
461: break;
462: case Const.opc_putfield:
463: case Const.opc_putstatic: {
464: fref = (FMIrefConstant) cpool[getUnsignedShort(
465: code, locs[j] + 1)];
466: addCrossReference(md, fref, ARC_WRITES);
467: break;
468: }
469: case Const.opc_ldc_w: {
470: ConstantObject o = cpool[getUnsignedShort(code,
471: locs[j] + 1)];
472: if (o instanceof StringConstant) {
473: makeString(md);
474: } else if (o instanceof ClassConstant) {
475: conditionalClassReference(md,
476: (ClassConstant) o, ARC_CLASS);
477: }
478: break;
479: }
480: case Const.opc_invokeinterface:
481: case Const.opc_invokevirtual:
482: case Const.opc_invokespecial:
483: case Const.opc_invokestatic:
484: fref = (FMIrefConstant) cpool[getUnsignedShort(
485: code, locs[j] + 1)];
486: addCrossReference(md, fref, ARC_CALLS);
487: break;
488: }
489: }
490: } catch (Exception e) {
491: System.out.println(this );
492: e.printStackTrace();
493: break doCode;
494: }
495: }
496: return md;
497: }
498:
499: private MemberDependenceNode parseFieldInfo(FieldInfo fi) {
500: return parseClassMemberInfo(fi, MemberDependenceNode.FIELD);
501: }
502:
503: private MemberDependenceNode parseClassMemberInfo(
504: ClassMemberInfo mi, int flagval) {
505: boolean isStatic = (mi.isStaticMember())
506: || (mi.name.string.charAt(0) == '<');
507:
508: if (isStatic)
509: flagval |= MemberDependenceNode.STATIC;
510: if (mi.isPrivateMember())
511: flagval |= MemberDependenceNode.PRIVATE;
512: if (mi.name.string.equals("<init>"))
513: flagval |= MemberDependenceNode.INIT;
514: if (mi.name.string.equals("<clinit>"))
515: flagval |= MemberDependenceNode.CLINIT;
516: if ((mi.access & Const.ACC_NATIVE) != 0)
517: flagval |= MemberDependenceNode.NATIVE;
518:
519: String memberName = mi.name.string;
520: if ((flagval & MemberDependenceNode.METHOD) != 0)
521: memberName += mi.type.string;
522: return lookupAddMember(new MemberName(this , memberName),
523: flagval);
524: }
525:
526: private boolean imputeMembers(ClassEntry other) {
527: if (other == null)
528: return true; // vacuous
529: if (other.nodeState == UNANALYZED)
530: other.analyzeClass(cdict);
531: if (other.nodeState == ERROR)
532: return false;
533: if (other.memberSet != null) {
534: Enumeration omembers = other.memberSet.elements();
535: while (omembers.hasMoreElements()) {
536: MemberDependenceNode mn = (MemberDependenceNode) (omembers
537: .nextElement());
538: if ((mn.flags & MemberDependenceNode.NO_OVERRIDING) != 0)
539: continue; // never mind. Not part of interface.
540: MemberName tname = (MemberName) (((MemberName) (mn
541: .name())).clone());
542: tname.classEntry = this ;
543: MemberDependenceNode ourmn = lookupAddMember(tname, 0);
544: if ((ourmn.flags & ~EXCLUDED) == 0) {
545: // no flags set. That means that we just inserted it.
546: ourmn.flags |= mn.flags
547: | MemberDependenceNode.IMPUTED;
548: }
549: }
550: }
551: if (!imputeMembers(other.super ClassEntry))
552: return false;
553: if (other.interfaceSet != null) {
554: Enumeration ilist = other.interfaceSet.elements();
555: while (ilist.hasMoreElements()) {
556: if (!imputeMembers((ClassEntry) (ilist.nextElement())))
557: return false;
558: }
559: }
560: return true;
561: }
562:
563: private void addSubclass(ClassEntry newSub) {
564: if (subclassSet == null) {
565: subclassSet = new Vector();
566: }
567: subclassSet.addElement(newSub);
568: }
569:
570: private boolean hasSubclass(ClassEntry other) {
571: if (subclassSet == null)
572: return false;
573: Enumeration subs = subclassSet.elements();
574: while (subs.hasMoreElements()) {
575: if (subs.nextElement() == other)
576: return true;
577: }
578: subs = subclassSet.elements();
579: while (subs.hasMoreElements()) {
580: if (((ClassEntry) (subs.nextElement())).hasSubclass(other))
581: return true;
582: }
583: return false;
584: }
585:
586: class ParamSignatureParser extends util.SignatureIterator {
587: String params[];
588: MemberDependenceNode ref;
589:
590: public ParamSignatureParser(String sig, MemberDependenceNode r) {
591: super (sig);
592: ref = r;
593: }
594:
595: public void do_array(int arrayDepth, int subTypeStart,
596: int subTypeEnd) {
597: ClassEntry cer;
598: DependenceArc da;
599:
600: if (subTypeStart == subTypeEnd)
601: return;
602:
603: cer = cdict.lookupAdd(sig.substring(subTypeStart + 1,
604: subTypeEnd));
605: da = new DependenceArc(ref, cer, ARC_CLASS);
606: ref.nodeDependsOn.addElement(da);
607: cer.nodeDependedOn.addElement(da);
608: }
609:
610: public void do_object(int subTypeStart, int subTypeEnd) {
611: ClassEntry cer;
612: DependenceArc da;
613:
614: cer = cdict.lookupAdd(sig.substring(subTypeStart + 1,
615: subTypeEnd));
616: da = new DependenceArc(ref, cer, ARC_CLASS);
617: ref.nodeDependsOn.addElement(da);
618: cer.nodeDependedOn.addElement(da);
619: }
620:
621: }
622:
623: }
|