/* * * * Copyright 1990-2009 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; /* * VM-specific internal representation of * a class. Target-machine independent. * There is a references from each instance of components.ClassInfo to * one of these, and a reference back as well. * * See also JDKVM for VM-specific info not associated directly with a class. */ import components.*; import util.*; import jcc.Const; import jcc.Str2ID; import java.util.Enumeration; import java.util.Vector; import java.util.Hashtable; import java.util.StringTokenizer; public class ClassClass { public ClassInfo ci; public InterfaceMethodTable inf; public boolean impureConstants = false; public int nGCStatics = 0; public boolean hasStaticInitializer = false; protected static int finalizerID = Str2ID.sigHash.getID(/*NOI18N*/"finalize", /*NOI18N*/"()V" ); public MethodConstant findFinalizer( ){ if ( ci == null ) return null; if ( ci.refMethodtable == null ) return null; int n = ci.refMethodtable.length; for ( int i = 0; i < n ; i++ ){ MethodConstant mc= ci.refMethodtable[i]; if ( mc.getID() == finalizerID ){ if ( mc.find().parent.superClass == null ){ /* * since we know that java.lang.Object's * finalizer does nothing, we can ignore * its existence! */ return null; } return mc; } } return null; } public static void setTypes(){ classFactory.setTypes(); } /* * Make the class list into a vector * ordered s.t. superclasses precede their * subclasses. */ private static ClassClass[]cvector; private static int cindex; private static VMClassFactory classFactory; // this is the recursive part private static void insertClassElement( ClassInfo e ){ if ( e.vmClass != null ) return; // already in place. ClassInfo sup = e.superClassInfo; // make sure our super precedes us. if ( (sup != null) && (sup.vmClass == null) ) insertClassElement( sup ); ClassClass newVmClass = classFactory.newVMClass( e ); cvector[ cindex++ ] = newVmClass; // // If the superclass of class C has a <clinit> method, C must // be marked as having a static initializer too. // if (!newVmClass.hasStaticInitializer && (sup != null) && sup.vmClass.hasStaticInitializer) { newVmClass.hasStaticInitializer = true; } } // this is the entry point for vector building. public static ClassClass[] getClassVector( VMClassFactory ftry ){ if ( cvector != null ) return cvector; // just once, at most. classFactory = ftry; cvector = new ClassClass[ ClassInfo.nClasses() ]; cindex = 0; Enumeration classlist = ClassInfo.allClasses(); while( classlist.hasMoreElements() ){ ClassInfo e = (ClassInfo)classlist.nextElement(); if (e.vmClass == null) insertClassElement( e ); } return cvector; } public static void appendClassElement( ClassInfo c ){ // foo. Have a cvector in place, must now // add a new entry at the end. "c" is it. if ( cvector == null ) return; // ...never mind ClassClass[] oldCvector = cvector; cvector = new ClassClass[ cindex+1 ]; System.arraycopy( oldCvector, 0, cvector,0, cindex ); cvector[ cindex ] = classFactory.newVMClass( c ); } /** * Size of an instance in WORDS. */ public int instanceSize(){ FieldConstant rft[] = ci.refFieldtable; if ( rft == null || rft.length == 0 ) return 0; FieldInfo lastField = rft[rft.length-1].find(); return (lastField.instanceOffset+lastField.nSlots); } public boolean isInterface() { return (ci.access&Const.ACC_INTERFACE) != 0; } public boolean hasMethodtable(){ return ((!isInterface()) && (ci.refMethodtable != null)); } public boolean isArrayClass(){ return (ci instanceof ArrayClassInfo); } public boolean isPrimitiveClass() { return (ci instanceof PrimitiveClassInfo); } public int nmethods(){ return (ci.methods==null) ? 0 : ci.methods.length; } public int nfields(){ return (ci.fields==null) ? 0 : ci.fields.length; } /** * In the current definition of module (.mclass) files, * many sorts of constants are put in the shared constant * pool, and never in the per-class constant pool. This includes * Unicode constants and NameAndType constants. This is fine * as long as all symbols in the per-class constant pools get * resolved, as they won't be missed. However, if we wish to * process classes with symbol references that are not fully * resolved, we will have to add such elements into the constant * pool. We do this by sweeping over the per-class constants, * looking for method, field, and class references that are not * resolved, and adding the necessary entries. */ public void adjustSymbolicConstants(){ ConstantObject consts[] = ci.constants; if (!isPartiallyResolved(consts)) { return; } // // we have work to do. This is unfortunate. // we use a LocalConstantPool to manage the pool we're re-building. // Because order matters, we collect the new entries to add at end. // //System.err.println(Localizer.getString("classclass.warning_class_has_an_impure_constant_pool", ci.className)); ci.constants = makeResolvable(consts).getConstants(); impureConstants = true; } public static boolean isPartiallyResolved( ConstantObject[] consts ){ if ( consts == null ) return false; // no const! int nconst = consts.length; if ( nconst == 0 ) return false; // no const! // first see if we have anything that needs our attention. int nsymbolic = 0; for( int i = 1; i < nconst; i += consts[i].nSlots ){ ConstantObject o = consts[i]; if (!o.isResolved()) { return true; } } return false; } static public ConstantPool makeResolvable(ConstantPool cp) { // // we use a LocalConstantPool to manage the pool we're re-building. // Because order matters, we collect the new entries to add at end. // System.err.println(Localizer.getString("classclass.warning_it_has_an_impure_shared_constant_pool")); return makeResolvable(cp.getConstants()); } static private ConstantPool makeResolvable(ConstantObject[] consts) { LocalConstantPool newPool = new LocalConstantPool(); Vector newEntries = new Vector(); int nconst = consts.length; for( int i = 1; i < nconst; i += consts[i].nSlots ){ ConstantObject o; o = consts[i]; newPool.append(o); if ( ! o.isResolved() ) newEntries.addElement( o ); } Enumeration newlist = newEntries.elements(); while( newlist.hasMoreElements() ){ ConstantObject o = (ConstantObject)newlist.nextElement(); switch( o.tag ){ case Const.CONSTANT_CLASS: ClassConstant co = (ClassConstant)o; System.err.println(Localizer.getString("classclass.class", co.name.string)); co.name = (UnicodeConstant)newPool.add( co.name ); continue; case Const.CONSTANT_FIELD: case Const.CONSTANT_METHOD: case Const.CONSTANT_INTERFACEMETHOD: FMIrefConstant fo = (FMIrefConstant)o; if ( fo.clas.isResolved() && false ){ // This is a missing member of a resolved class. // Print this out // To print all the references to a totally missing // class would be redundant and noisy. if ( fo.tag == Const.CONSTANT_FIELD ){ System.err.print(Localizer.getString("classclass.field")); } else { System.err.print(Localizer.getString("classclass.method")); } System.err.println(Localizer.getString( "classclass.of_class", fo.sig.name.string, fo.sig.type.string, fo.clas.name.string)); } // as NameAndTypeConstant entries are always "resolved", // the strings they nominally point to need not be present: // they will get written out as a hash ID. fo.sig = (NameAndTypeConstant)newPool.add( fo.sig ); fo.clas.name = (UnicodeConstant)newPool.add( fo.clas.name ); fo.clas = (ClassConstant)newPool.add( fo.clas ); continue; } } newPool.impureConstants = true; return newPool; } } /* * Like a constant pool, but with simpler semantics. * Perhaps this and components.ConstantPool should be related. * The important difference is in "add", which never shares * and which always clones if it must insert! * Also append, which is even simpler, as it assumes that we're * loading up this constant pool from an already-existing list. */ final class LocalConstantPool extends components.ConstantPool { public LocalConstantPool(){ super(); } /** * Return the ConstantObject in constant table corresponding to * the given ConstantObject s. * Duplicates and inserts s if it is not already there. * The index member of the returned value (which * will not be the object s!) will be set to its index in our * table. There will be no element of index 0. */ public ConstantObject add( ConstantObject s ){ ConstantObject r = (ConstantObject)h.get( s ); if ( r == null ){ r = (ConstantObject)s.clone(); r.index = n; n += r.nSlots; h.put( r, r ); t.addElement( r ); for ( int i =r.nSlots; i > 1; i-- ) t.addElement( null ); // place holder. } r.references+=1; return r; } public void append( ConstantObject s ){ if ( h.get( s ) != null ){ throw new Error(Localizer.getString( "classclass.append.error_already_in_pool", s)); } if ( s.index != n ){ throw new Error(Localizer.getString( "classclass.append.error_out_of_order", s)); } h.put( s, s); t.addElement( s ); s.references+=1; for ( int i =s.nSlots; i > 1; i-- ) t.addElement( null ); // place holder. n += s.nSlots; } }