/*
* @(#)CVMInterfaceMethodTable.java 1.23 06/10/10
*
* Copyright 1990-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*
*/
package runtime;
import vm.*;
import components.*;
import consts.Const;
import java.util.Hashtable;
/*
* This is the CVM-specific subclass of vm.InterfaceMethodTable
* It knowns how to write out these data structures for the CVM
* This is similar to the CInterfaceMethodTable used for
* JDK1.1-based systems. The substantial difference is
* the ordering requirement: rather than having two representations
* of interfaces, CVM has only one. Those this class implements
* directly come first, followed by those inhereted.
* Also note that the count of interfaced declared by the class is part of this
* structure. This would seem to limit the ability of a child class to share data
* with its parent in the case where the parent declares an interface
* but the child does not. The CVM recognizes this case though, so this
* sharing is allowed. Here's an odd example:
* class a implements Serializeable {}
* class b extends a {}
* // b shares a's interface table
* class c extends a implements Serializeable {}
* // c cannot share a's interface table
* // though they are identical!
*/
class CVMInterfaceMethodTable extends vm.InterfaceMethodTable {
// names we generate
public static final String vectorName = "CVMinterfaceVector";
int implementsCount;
boolean generated;
public
CVMInterfaceMethodTable( ClassClass c, String n, InterfaceVector v[] ){
super( c, n, v );
implementsCount = (c.classInfo.interfaces == null) ?
0 : c.classInfo.interfaces.length;
generated = false;
}
private static void
sortInterfaceVectors( ClassInfo c, InterfaceVector v[], boolean isInterface ){
/*
* Each of these interface vectors is correct, BUT order matters
* We want to make sure that the entries for interfaces declared directly
* by us come first in the list, AND that they are in the order declared!
* so do a simple sort of them here.
*/
ClassConstant interfaces[] = c.interfaces;
int implementsCount = interfaces.length;
int l = v.length;
for ( int i = 0; i < implementsCount; i++ ){
ClassInfo thisInterface = interfaces[i].find();
for ( int j = i; j < l; j++ ){
if ( v[j].intf == thisInterface ){
if ( i != j ){
// swap
InterfaceVector t = v[i];
v[i] = v[j];
v[j] = t;
}
break;
}
}
}
if ( isInterface ){
/*
* put this class itself next.
*/
// this will fail badly if this class is not present.
int j = implementsCount;
while ( v[j].intf != c ){
j++;
}
if ( j != implementsCount ){
// swap
InterfaceVector t = v[implementsCount];
v[implementsCount] = v[j];
v[j] = t;
}
}
}
private static InterfaceMethodTable
generateTablesForInterface( ClassInfo c ){
//
// We generate a thing like an imethodtable for interfaces, too.
// But its different enough that I'm treating it separately, here.
//
// Cannot share our imethotable with our superclass,
// as it must at least include ourselves!
//
ClassClass me = c.vmClass;
int ntotal = c.allInterfaces.size();
InterfaceVector ivec[] = new InterfaceVector[ ntotal+1 ];
// first the entry for ourselves.
ivec[ 0 ] = new InterfaceVector( me, c, null );
// now all the others (if any)
for( int i = 0; i< ntotal; i++){
ClassInfo intf = (ClassInfo)c.allInterfaces.elementAt( i );
ivec[ i+1 ] = new InterfaceVector( me, intf, null );
}
sortInterfaceVectors( c, ivec, true );
return new CVMInterfaceMethodTable(
c.vmClass, "CVM_"+c.getGenericNativeName()+"_intfMethodtable", ivec );
}
/*
* Modified version from vm.InterfaceMethodTable for
* handling the special ordering and sharing needs of CVM.
*/
public static InterfaceMethodTable
generateInterfaceTable( ClassClass cc ){
ClassInfo c = cc.classInfo;
if ( c.allInterfaces == null )
c.findAllInterfaces();
ClassInfo sup = c.superClassInfo;
int ntotal = c.allInterfaces.size();
int nsuper = 0;
int implementsCount = (c.interfaces==null)?0:c.interfaces.length;
if ( (c.access&Const.ACC_INTERFACE) != 0 ){
return generateTablesForInterface( c );
}
if ( sup != null ){
if ( sup.vmClass.inf == null ){
// generate parental information,
// that we might borrow it.
sup.vmClass.inf = generateInterfaceTable( sup.vmClass );
}
if ( implementsCount == 0 ){
// CVM allows sharing with parent if we have no
// declared interfaces ourselves.
// use other class's tables entirely.
// we have nothing further to add.
return sup.vmClass.inf;
}
}
//
// generate the offset tables, or symbolic references
// to them.
InterfaceVector vec[] = new InterfaceVector[ ntotal ];
if ( nsuper != 0 ){
// borrow some from superclass. They are the same.
System.arraycopy( sup.vmClass.inf.iv, 0, vec, 0, nsuper );
}
// compute the rest of the thing ourselves.
for( int i = nsuper; i < ntotal; i++ ){
ClassInfo intf = (ClassInfo)c.allInterfaces.elementAt( i );
vec[ i ] = generateInterfaceVector( c, intf );
}
/*
* Each of these interface vectors is correct, BUT order matters
* We want to make sure that the entries for interfaces declared directly
* by us come first in the list, AND that they are in the order declared!
* so do a simple sort of them here.
*/
sortInterfaceVectors( c, vec, false );
return new CVMInterfaceMethodTable(
cc, "CVM_"+c.getGenericNativeName()+"_intfMethodtable", vec );
}
static void writeInterfaceTables(ClassClass[] classes, CCodeWriter out, CCodeWriter headerOut) {
int n = classes.length;
// generate the tables. generateInterfaceTable must work
// recursively, of course!
for ( int i = 0; i < n; i++ ){
ClassClass c = classes[i];
if ( c.inf == null )
c.inf = generateInterfaceTable(c );
}
//
// print the vectors first.
//
out.println( "STATIC const CVMUint16 " + vectorName + "[] = {");
int offset = 0;
boolean emptyVector = true;
for (int i = 0; i < n; i++) {
ClassClass c = classes[i];
CVMInterfaceMethodTable simt = (CVMInterfaceMethodTable)c.inf;
if (simt == null || simt.parent != c)
continue;
InterfaceVector iv[] = simt.iv;
for (int j = 0; j < iv.length; j++) {
InterfaceVector vec = iv[j];
if ( vec.generated )
continue; // done.
vec.generated = true;
vec.offset = offset;
short vector[] = vec.v;
if ( (vector==null) || (vector.length == 0) ){
continue;
}
int num = vector.length;
emptyVector = false;
out.comment(simt.parent.classInfo.className +
" " + vec.intf.className);
for (int k = 0, mod = 0; k < num; k++) {
if (mod == 0) out.write('\t');
out.printHexInt( vector[k] );
out.write(',');
if (++mod == 8) {
out.write('\n'); mod = 0;
}
}
if ((num % 8) != 0)
out.write('\n');
offset += num;
}
}
if ( emptyVector ){
out.write('0');// make it non-empty!
}
out.println("};\n");
// end vectors.
//
// now write out the CVMInterfaces structures, which
// roughly correspond to the InterfaceMethodTables.
// But not quite.
//
for (int i = 0; i < n; i++) {
ClassClass c = classes[i];
CVMInterfaceMethodTable simt = (CVMInterfaceMethodTable)c.inf;
if ( simt != null ){
simt.write(out, headerOut);
}
}
}
private static boolean
needVector( InterfaceVector vec ){
if ( vec.v == null || vec.v.length == 0 ) return false; // don't bother.
return true;
}
private static java.util.BitSet interfaceSizes = new java.util.BitSet();
private static final String interfaceStructName = "CVMinterface";
//struct CVMInterfaces {
// CVMUint16 interfaceCount;
// CVMUint16 implementsCount;
// union {
// CVMUint16* interfaces;
// struct {
// CVMClassBlock* interfacecb;
// CVMUint16* index;
// } interfaceTable[1];
// } intfInfo;
//};
private static String declareInterfaceStruct( int n, CCodeWriter out ){
String interfaceFlavor = "union "+interfaceStructName+n;
if ( ! interfaceSizes.get( n ) ){
out.println(interfaceFlavor+" {");
out.println(" struct {");
out.println(" CVMUint16 interfaceCount; CVMUint16 implementsCount;");
out.println(" struct { const CVMClassBlock* interfacecb;" +
" union {CVMUint16 * addr; CVMClassTypeID ti;} ext;" +
"} interfaceTable["+n+"];");
out.println(" } dontAccess;");
out.println(" CVMInterfaces interfaces;");
out.println("};");
interfaceSizes.set( n );
}
return interfaceFlavor;
}
public void
write( CCodeWriter out, CCodeWriter headerOut){
if (this.generated)
return;
this.generated = true;
if ( iv.length == 0 ){
// omit structures of length 0
return;
}
String structType = declareInterfaceStruct( iv.length, headerOut );
/*
* Added 'extern' keyword, so that the header file does not
* declare an (unnecessary) global variable for each struct
* declaration (which would never be used anyway) */
headerOut.println("extern const "+structType+" "+name+";");
out.print("const "+structType+" "+name);
out.print(" = {{\n\t");
out.print( iv.length );
out.print(", ");
out.print( implementsCount );
out.println(", {");
for( int i = 0; i < iv.length; i++ ){
InterfaceVector entry = iv[i];
ClassInfo intf = entry.intf;
String intfName = intf.getGenericNativeName();
out.print("\t{ ");
out.print("(CVMClassBlock*)&"+intfName);
out.print("_Classblock.classclass,");
if ( needVector( entry ) ){
/*
* Cast to first type in union (CVMUint16 *).
*/
out.print("{(CVMUint16 *)&"+vectorName+"["+entry.offset+"]}");
} else {
/*
* Cast to first type in union (CVMUint16 *).
*/
out.print("{(CVMUint16 *)0}");
}
out.println(" },");
}
out.write('}');
out.println("}};");
}
}