001: /*
002: *
003: *
004: * Copyright 1990-2007 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: package jcc;
028:
029: import java.io.PrintStream;
030: import java.io.InputStream;
031: import java.io.StreamTokenizer;
032: import java.io.IOException;
033: import java.util.Hashtable;
034: import java.util.Vector;
035: import java.util.Enumeration;
036: import util.*;
037: import components.*;
038: import util.ClassFile;
039:
040: /*
041: * MemberLoader is the Jld subsystem
042: * which processes the -memberlist option.
043: * It reads the named file,
044: * it causes class files to be read if necessary,
045: * it manipulates the ClassInfo structures
046: * by marking members to be included.
047: * and finally it expunges all references to unwanted members.
048: */
049:
050: public class MemberLoader {
051: String fname;
052: StreamTokenizer in;
053: ClassFileFinder finder;
054: ClassReader rdr;
055:
056: public MemberLoader(ClassReader r, ClassFileFinder f) {
057: rdr = r;
058: finder = f;
059: }
060:
061: private ClassInfo enterClass(String classname, Vector v) {
062: ClassInfo ce;
063: classname = classname.intern();
064: ce = components.ClassInfo.lookupClass(classname);
065: if (ce != null)
066: return ce;
067:
068: if (rdr.readClass(classname, finder, v) != 1) {
069: //could not find anywhere.
070: System.err.println(Localizer.getString(
071: "memberloader.could_not_find_class", classname));
072: return null; // or worse...
073: }
074: ce = (ClassInfo) (v.lastElement());
075: //
076: // we know that this was loaded on account of us.
077: // unlike most classes, this one will start life
078: // as empty, with no members assumed.
079: ce.flags &= ~(ClassInfo.INCLUDE_ALL);
080: ce.clearMemberFlags(ClassMemberInfo.INCLUDE);
081: return ce;
082: }
083:
084: private boolean enterMember(ClassInfo ce, String name) {
085: if ((ce.flags & ClassInfo.INCLUDE_ALL) != 0) {
086: return true; // doesn't matter what we do anyway!
087: }
088: ClassMemberInfo t[];
089: String sig;
090: // determine if this is data or method by looking
091: // at the signature, or lack thereof.
092: int sigstart = name.indexOf('(');
093: if (sigstart == -1) {
094: // this is data.
095: // too bad we cannot use the standard procedure
096: // that components/FMIrefConstant.find() uses,
097: // but we cannot because the hash ID requires
098: // data type signature information, which we lack.
099: t = ce.fields;
100: sig = null;
101: } else {
102: // this is code.
103: //
104: sig = name.substring(sigstart);
105: name = name.substring(0, sigstart);
106: t = ce.methods;
107: }
108: int l = t.length;
109: for (int i = 0; i < l; i++) {
110: if (t[i].name.string.equals(name)) {
111: if ((sig == null) || sig.equals(t[i].type.string)) {
112: t[i].flags |= ClassMemberInfo.INCLUDE;
113: return true; // done.
114: }
115: }
116: }
117: System.err.println(Localizer.getString(
118: "memberloader.could_not_find_member", ce.className,
119: name));
120: return false;
121: }
122:
123: private void openStream(String name) throws IOException {
124: fname = name;
125: in = new StreamTokenizer(new java.io.BufferedInputStream(
126: new java.io.FileInputStream(fname)));
127: in.resetSyntax();
128: in.eolIsSignificant(true);
129: in.whitespaceChars(0, 0x20);
130: in.wordChars('!', '~');
131: in.commentChar('#');
132: in.ordinaryChar('.');
133:
134: }
135:
136: private void oops(String lmsg) throws DataFormatException {
137: String errmsg = Localizer.getString(
138: "memberloader.dependence_file_error_near_line", fname,
139: Integer.toString(in.lineno()));
140: if (lmsg != null) {
141: errmsg += Localizer.getString(lmsg);
142: }
143: in = null; // when we bail, close the file.
144: throw new DataFormatException(errmsg);
145: }
146:
147: /*
148: * Read output of JavaFilter
149: */
150: public void readFromFile(String fname, Vector classlist)
151: throws DataFormatException, IOException {
152: int t;
153: openStream(fname);
154: while ((t = in.nextToken()) != StreamTokenizer.TT_EOF) {
155: /*
156: * Process a line of input. It may be empty
157: * or contain only a comment.
158: * Else there must be a class name.
159: * If the class name is followed by a .,
160: * then a member name follows. The name
161: * will include a signature, if a method is named.
162: * No signature is needed for data members.
163: */
164: if (t == StreamTokenizer.TT_EOL)
165: continue;
166: String className;
167: String memberName;
168: String sig;
169: if (t != StreamTokenizer.TT_WORD)
170: oops("memberloader.missing_classname");
171: className = in.sval;
172: ClassInfo ce = enterClass(className, classlist);
173: if ((t = in.nextToken()) == StreamTokenizer.TT_EOL) {
174: continue; // class name only
175: }
176: if (t != '.') {
177: oops("memberloader.syntax_error");
178: continue;
179: }
180: if ((t = in.nextToken()) != StreamTokenizer.TT_WORD) {
181: oops("memberloader.malformed_member_name");
182: continue;
183: }
184: memberName = in.sval;
185: /*
186: * Now that we've read the names, process it.
187: */
188: if (ce != null)
189: enterMember(ce, memberName);
190:
191: if (in.nextToken() != StreamTokenizer.TT_EOL)
192: oops("memberloader.extra_material");
193: }
194: in = null; // close the file.
195: }
196:
197: /*
198: * Traverse the class list.
199: * Delete unneeded methods!!
200: */
201:
202: private int deleteMembers(ClassMemberInfo mlist[]) {
203: if (mlist == null || mlist.length == 0)
204: return 0; // trivial case.
205: int n = mlist.length;
206: int ndeleted = 0;
207: for (int i = 0; i < n; i++) {
208: if ((mlist[i].flags & ClassMemberInfo.INCLUDE) == 0) {
209: mlist[i].index = -1; // obvious error value.
210: mlist[i] = null;
211: ndeleted += 1;
212: }
213: }
214: return ndeleted;
215: }
216:
217: private static void copyNonNull(ClassMemberInfo from[],
218: ClassMemberInfo to[]) {
219: int n = from.length;
220: int j = 0;
221: for (int i = 0; i < n; i++) {
222: if (from[i] != null) {
223: from[i].index = j;
224: to[j++] = from[i];
225: }
226: }
227: }
228:
229: private void loadMembers(ClassInfo ci) {
230: int ndeleted = deleteMembers(ci.methods);
231: if (ndeleted != 0) {
232: int n = ci.methods.length;
233: MethodInfo newlist[] = new MethodInfo[n - ndeleted];
234: copyNonNull(ci.methods, newlist);
235: ci.methods = newlist;
236: }
237: ndeleted = deleteMembers(ci.fields);
238: if (ndeleted != 0) {
239: int n = ci.fields.length;
240: FieldInfo newlist[] = new FieldInfo[n - ndeleted];
241: copyNonNull(ci.fields, newlist);
242: ci.fields = newlist;
243: }
244: }
245:
246: /*
247: * This is serious!
248: * Iterate through all our classes.
249: * Look at all the members
250: * When I see one that doesn't have isLoaded set,
251: * just delete it!
252: */
253: public void deleteUnwantedMembers(Vector classes) {
254: Enumeration e = classes.elements();
255: while (e.hasMoreElements()) {
256: ClassInfo ci = (ClassInfo) e.nextElement();
257: if ((ci.flags & ClassInfo.INCLUDE_ALL) != 0)
258: continue; // a fully-loaded class.
259: loadMembers(ci);
260: }
261: }
262:
263: }
|