001: /*
002: * @(#)CVMInterfaceMethodTable.java 1.23 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 runtime;
029:
030: import vm.*;
031: import components.*;
032: import consts.Const;
033: import java.util.Hashtable;
034:
035: /*
036: * This is the CVM-specific subclass of vm.InterfaceMethodTable
037: * It knowns how to write out these data structures for the CVM
038: * This is similar to the CInterfaceMethodTable used for
039: * JDK1.1-based systems. The substantial difference is
040: * the ordering requirement: rather than having two representations
041: * of interfaces, CVM has only one. Those this class implements
042: * directly come first, followed by those inhereted.
043: * Also note that the count of interfaced declared by the class is part of this
044: * structure. This would seem to limit the ability of a child class to share data
045: * with its parent in the case where the parent declares an interface
046: * but the child does not. The CVM recognizes this case though, so this
047: * sharing is allowed. Here's an odd example:
048: * class a implements Serializeable {}
049: * class b extends a {}
050: * // b shares a's interface table
051: * class c extends a implements Serializeable {}
052: * // c cannot share a's interface table
053: * // though they are identical!
054: */
055:
056: class CVMInterfaceMethodTable extends vm.InterfaceMethodTable {
057:
058: // names we generate
059: public static final String vectorName = "CVMinterfaceVector";
060:
061: int implements Count;
062: boolean generated;
063:
064: public CVMInterfaceMethodTable(ClassClass c, String n,
065: InterfaceVector v[]) {
066: super (c, n, v);
067: implements Count = (c.ci.interfaces == null) ? 0
068: : c.ci.interfaces.length;
069: generated = false;
070: }
071:
072: private static void sortInterfaceVectors(ClassInfo c,
073: InterfaceVector v[], boolean isInterface) {
074: /*
075: * Each of these interface vectors is correct, BUT order matters
076: * We want to make sure that the entries for interfaces declared directly
077: * by us come first in the list, AND that they are in the order declared!
078: * so do a simple sort of them here.
079: */
080: ClassConstant interfaces[] = c.interfaces;
081: int implements Count = interfaces.length;
082: int l = v.length;
083: for (int i = 0; i < implements Count; i++) {
084: ClassInfo this Interface = interfaces[i].find();
085: for (int j = i; j < l; j++) {
086: if (v[j].intf == this Interface) {
087: if (i != j) {
088: // swap
089: InterfaceVector t = v[i];
090: v[i] = v[j];
091: v[j] = t;
092: }
093: break;
094: }
095: }
096: }
097: if (isInterface) {
098: /*
099: * put this class itself next.
100: */
101: // this will fail badly if this class is not present.
102: int j = implements Count;
103: while (v[j].intf != c) {
104: j++;
105: }
106: if (j != implements Count) {
107: // swap
108: InterfaceVector t = v[implements Count];
109: v[implements Count] = v[j];
110: v[j] = t;
111: }
112: }
113: }
114:
115: private static InterfaceMethodTable generateTablesForInterface(
116: ClassInfo c) {
117: //
118: // We generate a thing like an imethodtable for interfaces, too.
119: // But its different enough that I'm treating it separately, here.
120: //
121: // Cannot share our imethotable with our superclass,
122: // as it must at least include ourselves!
123: //
124: ClassClass me = c.vmClass;
125: int ntotal = c.allInterfaces.size();
126: InterfaceVector ivec[] = new InterfaceVector[ntotal + 1];
127:
128: // first the entry for ourselves.
129: ivec[0] = new InterfaceVector(me, c, null);
130: // now all the others (if any)
131: for (int i = 0; i < ntotal; i++) {
132: ClassInfo intf = (ClassInfo) c.allInterfaces.elementAt(i);
133: ivec[i + 1] = new InterfaceVector(me, intf, null);
134: }
135: sortInterfaceVectors(c, ivec, true);
136: return new CVMInterfaceMethodTable(c.vmClass, "CVM_"
137: + c.getGenericNativeName() + "_intfMethodtable", ivec);
138: }
139:
140: /*
141: * Modified version from vm.InterfaceMethodTable for
142: * handling the special ordering and sharing needs of CVM.
143: */
144: public static InterfaceMethodTable generateInterfaceTable(
145: ClassClass cc) {
146: ClassInfo c = cc.ci;
147: if (c.allInterfaces == null)
148: c.findAllInterfaces();
149: ClassInfo sup = c.super ClassInfo;
150: int ntotal = c.allInterfaces.size();
151: int nsuper = 0;
152: int implements Count = (c.interfaces == null) ? 0
153: : c.interfaces.length;
154:
155: if ((c.access & Const.ACC_INTERFACE) != 0) {
156: return generateTablesForInterface(c);
157: }
158: if (sup != null) {
159: if (sup.vmClass.inf == null) {
160: // generate parental information,
161: // that we might borrow it.
162: sup.vmClass.inf = generateInterfaceTable(sup.vmClass);
163: }
164: if (implements Count == 0) {
165: // CVM allows sharing with parent if we have no
166: // declared interfaces ourselves.
167: // use other class's tables entirely.
168: // we have nothing further to add.
169: return sup.vmClass.inf;
170: }
171: }
172: //
173: // generate the offset tables, or symbolic references
174: // to them.
175: InterfaceVector vec[] = new InterfaceVector[ntotal];
176: if (nsuper != 0) {
177: // borrow some from superclass. They are the same.
178: System.arraycopy(sup.vmClass.inf.iv, 0, vec, 0, nsuper );
179: }
180:
181: // compute the rest of the thing ourselves.
182: for (int i = nsuper ; i < ntotal; i++) {
183: ClassInfo intf = (ClassInfo) c.allInterfaces.elementAt(i);
184: vec[i] = generateInterfaceVector(c, intf);
185: }
186:
187: /*
188: * Each of these interface vectors is correct, BUT order matters
189: * We want to make sure that the entries for interfaces declared directly
190: * by us come first in the list, AND that they are in the order declared!
191: * so do a simple sort of them here.
192: */
193: sortInterfaceVectors(c, vec, false);
194:
195: return new CVMInterfaceMethodTable(cc, "CVM_"
196: + c.getGenericNativeName() + "_intfMethodtable", vec);
197: }
198:
199: static void writeInterfaceTables(ClassClass[] classes,
200: CCodeWriter out, CCodeWriter headerOut) {
201:
202: int n = classes.length;
203: // generate the tables. generateInterfaceTable must work
204: // recursively, of course!
205: for (int i = 0; i < n; i++) {
206: ClassClass c = classes[i];
207: if (c.inf == null)
208: c.inf = generateInterfaceTable(c);
209: }
210:
211: //
212: // print the vectors first.
213: //
214: out.println("STATIC const CVMUint16 " + vectorName + "[] = {");
215: int offset = 0;
216: boolean emptyVector = true;
217: for (int i = 0; i < n; i++) {
218: ClassClass c = classes[i];
219: CVMInterfaceMethodTable simt = (CVMInterfaceMethodTable) c.inf;
220: if (simt == null || simt.parent != c)
221: continue;
222: InterfaceVector iv[] = simt.iv;
223: for (int j = 0; j < iv.length; j++) {
224: InterfaceVector vec = iv[j];
225: if (vec.generated)
226: continue; // done.
227: vec.generated = true;
228: vec.offset = offset;
229: short vector[] = vec.v;
230: if ((vector == null) || (vector.length == 0)) {
231: continue;
232: }
233: int num = vector.length;
234: emptyVector = false;
235: out.comment(simt.parent.ci.className + " "
236: + vec.intf.className);
237: for (int k = 0, mod = 0; k < num; k++) {
238: if (mod == 0)
239: out.write('\t');
240: out.printHexInt(vector[k]);
241: out.write(',');
242: if (++mod == 8) {
243: out.write('\n');
244: mod = 0;
245: }
246: }
247: if ((num % 8) != 0)
248: out.write('\n');
249: offset += num;
250: }
251: }
252: if (emptyVector) {
253: out.write('0');// make it non-empty!
254: }
255: out.println("};\n");
256: // end vectors.
257:
258: //
259: // now write out the CVMInterfaces structures, which
260: // roughly correspond to the InterfaceMethodTables.
261: // But not quite.
262: //
263: for (int i = 0; i < n; i++) {
264: ClassClass c = classes[i];
265: CVMInterfaceMethodTable simt = (CVMInterfaceMethodTable) c.inf;
266: if (simt != null) {
267: simt.write(out, headerOut);
268: }
269: }
270: }
271:
272: private static boolean needVector(InterfaceVector vec) {
273: if (vec.v == null || vec.v.length == 0)
274: return false; // don't bother.
275: return true;
276: }
277:
278: private static java.util.BitSet interfaceSizes = new java.util.BitSet();
279: private static final String interfaceStructName = "CVMinterface";
280:
281: //struct CVMInterfaces {
282: // CVMUint16 interfaceCount;
283: // CVMUint16 implementsCount;
284: // union {
285: // CVMUint16* interfaces;
286: // struct {
287: // CVMClassBlock* interfacecb;
288: // CVMUint16* index;
289: // } interfaceTable[1];
290: // } intfInfo;
291: //};
292:
293: private static String declareInterfaceStruct(int n, CCodeWriter out) {
294: String interfaceFlavor = "union " + interfaceStructName + n;
295: if (!interfaceSizes.get(n)) {
296: out.println(interfaceFlavor + " {");
297: out.println(" struct {");
298: out
299: .println(" CVMUint16 interfaceCount; CVMUint16 implementsCount;");
300: out
301: .println(" struct { const CVMClassBlock* interfacecb;"
302: + " union {CVMUint16 * addr; CVMClassTypeID ti;} ext;"
303: + "} interfaceTable[" + n + "];");
304: out.println(" } dontAccess;");
305: out.println(" CVMInterfaces interfaces;");
306: out.println("};");
307: interfaceSizes.set(n);
308: }
309: return interfaceFlavor;
310: }
311:
312: public void write(CCodeWriter out, CCodeWriter headerOut) {
313: if (this .generated)
314: return;
315: this .generated = true;
316: if (iv.length == 0) {
317: // omit structures of length 0
318: return;
319: }
320: String structType = declareInterfaceStruct(iv.length, headerOut);
321: /*
322: * Added 'extern' keyword, so that the header file does not
323: * declare an (unnecessary) global variable for each struct
324: * declaration (which would never be used anyway) */
325: headerOut.println("extern const " + structType + " " + name
326: + ";");
327: out.print("const " + structType + " " + name);
328: out.print(" = {{\n\t");
329: out.print(iv.length);
330: out.print(", ");
331: out.print(implements Count);
332: out.println(", {");
333: for (int i = 0; i < iv.length; i++) {
334: InterfaceVector entry = iv[i];
335: ClassInfo intf = entry.intf;
336: String intfName = intf.getGenericNativeName();
337: out.print("\t{ ");
338: out.print("(CVMClassBlock*)&" + intfName);
339: out.print("_Classblock.classclass,");
340: if (needVector(entry)) {
341: /*
342: * Cast to first type in union (CVMUint16 *).
343: */
344: out.print("{(CVMUint16 *)&" + vectorName + "["
345: + entry.offset + "]}");
346: } else {
347: /*
348: * Cast to first type in union (CVMUint16 *).
349: */
350: out.print("{(CVMUint16 *)0}");
351: }
352: out.println(" },");
353: }
354: out.write('}');
355: out.println("}};");
356: }
357: }
|