/* * @(#)InterfaceMethodTable.java 1.19 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 vm; import java.util.Hashtable; import java.util.Enumeration; import components.ClassInfo; import components.MethodInfo; import components.MethodConstant; import util.*; import consts.Const; /* * This class will build * the imethodtable, used by JDK1.1 for a quicker implementation * of invokeinterface_quick. * * This class should be subclassed in a target-machine-specific way * to provide writing out the data structure we build here. * See also InterfaceMethodFactory for the mechanism used to call back * into that target-specific body of code. * * Each ClassInfo is already decorated with a vector of * all the interfaces it implements. * Each ClassInfo's allInterfaces vector has its parent's vector as prefix. * So: * A) a class which implements the same number of interfaces as its parent * necessarily implements the same set of interfaces, and can use its * parent's table, by reference. * B) for those classes for which a table must indeed be built, * Only the interface elements associated with the present * ClassInfo need to have a method index table built. */ public abstract class InterfaceMethodTable { public ClassClass parent; public String name; public InterfaceVector iv[]; protected InterfaceMethodTable( ClassClass c, String n, InterfaceVector v[] ){ parent = c; name = n; iv = v; } private static MethodInfo findSlot( MethodInfo mit[], MethodInfo m ){ if ( mit != null ){ MethodInfo v; int nt = mit.length; int ID = m.getID(); for( int i = 0; i < nt; i++ ){ if ((v = mit[i]).getID() == ID ) return v; } } return null; } /* * Iterate through the methods of an interface. * For the non-static members (i.e. the non-<clinit> ) * assign a zero-based index, and use the methodTableIndex field * to keep it in. */ public void indexInterfaceMethods( ClassInfo c ){ if ( (c.access&Const.ACC_INTERFACE) == 0 ){ System.err.println(Localizer.getString("javacodecompact.not_an_interface", c.className)); return; // this is bad } int j = 0; MethodInfo m[] = c.methods; if ( m == null ) return; // no methods here. int n = m.length; for( int i =0; i < n; i++ ){ MethodInfo t = m[i]; if ( (t.access&Const.ACC_STATIC) != 0 ) continue; // don't number statics. if ( (t.access&Const.ACC_ABSTRACT) == 0 ){ System.err.println(Localizer.getString("javacodecompact.concrete_method_in_interface", c.className, t)); // but keep going anyway... } t.methodTableIndex = j++; } } private static InterfaceMethodTable generateTablesForInterface( ClassInfo c, String imtName, InterfaceMethodFactory imf ){ // // 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! // // struct imethodtable { // int icount; // struct { // ClassClass *classdescriptor; // unsigned long *offsets = 0; // } itable[1]; // } 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 ); } return imf.newInterfaceMethodTable( me, imtName, ivec ); } public static InterfaceVector generateInterfaceVector( ClassInfo thisClass, ClassInfo intf ){ MethodInfo mtab[] = intf.methodtable; int nmethods = mtab.length; short ivec[] = new short[ nmethods ]; for( int j = 0; j < nmethods; j++ ){ MethodInfo target = mtab[j]; if ( (target.access&Const.ACC_STATIC) != 0 ){ // should never happen. System.err.println(Localizer.getString( "javacodecompact.static_method_in_interface", intf.className, target)); continue; } MethodInfo v = findSlot( thisClass.methodtable, target ); if ( v == null ){ System.err.println(Localizer.getString( "javacodecompact.interface_unimplemented", thisClass.className, intf.className, target)); ivec[ j ] = 0; } else { ivec[ j ] = (short)v.methodTableIndex; } } return new InterfaceVector( thisClass.vmClass, intf, ivec ); } public static InterfaceMethodTable generateInterfaceTable( ClassClass cc, InterfaceMethodFactory imf ){ ClassInfo c = cc.classInfo; if (c.allInterfaces == null) { c.findAllInterfaces(); } String imtName = c.getGenericNativeName() + "_intfMethodtable"; ClassInfo sup = c.superClassInfo; int ntotal = c.allInterfaces.size(); int nsuper = 0; if ( (c.access&Const.ACC_INTERFACE) != 0 ){ return generateTablesForInterface( c, imtName, imf ); } if ( sup != null ){ if ( sup.vmClass.inf == null ){ // generate parental information, // that we might borrow it. sup.vmClass.inf = generateInterfaceTable( sup.vmClass, imf ); } nsuper = sup.allInterfaces.size(); if ( nsuper == ntotal ){ // 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 ); } return imf.newInterfaceMethodTable( cc, imtName, vec ); } }