/* * @(#)CVMDataType.java 1.9 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. * */ /* * CVM has a complex scheme for representing types as 16-bit * cookies. This code mimics the run-time code and thus builds the * corresponding data structures, to be ROMed. */ package vm; import java.util.Vector; import java.util.Enumeration; public abstract class CVMDataType implements CVMTypeCode, util.ClassFileConst { /* instance data */ /* Instances of this only appear in the * table. The only run-time external representation is * the cookie that references a table entry. Here are * the fields of the table. */ public int entryNo; public int typeNo; public CVMDataType next; // hash chain /* see also the sub-types which contain all the interesting instance data */ /* static data */ public static Vector dataTypes = new Vector(); static int nextEntryNo = 0; static int nextTypeNo = CVMtypeLastScalar+1; /* constructor &c */ static synchronized void enlist( CVMDataType x ){ x.entryNo = nextEntryNo++; x.typeNo = nextTypeNo++; dataTypes.addElement( x ); } CVMDataType(){ enlist( this ); } /* instance methods */ /* static methods */ /* * These really belong in CVMTypeCode... */ public static boolean isArray( int t ){ return (((t)&CVMtypeArrayMask) != 0 ); } public static boolean typeEquals( int t1, int t2 ){ return ((t1)==(t2)); } public static boolean isBigArray( int t ){ return (((t)&CVMtypeArrayMask)==CVMtypeBigArray); } /* * Return count of table entries. */ public static int nTableEntries(){ return dataTypes.size(); } /* * We use a very simple minded name hashing scheme. * Based on the LAST few letters of the name, which are * the most likely to differ, I believe. */ public static int computeHash( String name ){ int v = 0; int t = name.length(); int n = Math.min( t, 7 ); t -= n; while ( n--> 0 ){ v = (v*19) + name.charAt(t+n) - '/'; } return v; } /* * Class name is just a name, stripped of any envelopping * L...; */ static CVMClassDataType referenceClass( String className ){ // parse into class and package // package may be null, of course. // lookup package, use as primary key to finding // the class. int endPkg = className.lastIndexOf( SIGC_PACKAGE ); String pkgName; String classInPkg; if ( endPkg < 0 ){ pkgName = ""; classInPkg = className; } else { pkgName = className.substring(0,endPkg); classInPkg = className.substring(endPkg+1); } classInPkg = classInPkg.intern(); CVMpkg thisPkg = CVMpkg.lookup( pkgName ); // // have a package, have a class-name-in-package. // do simple lookup. int nameHash = computeHash( classInPkg ); /* make sure % is unsigned! */ int bucket = (int)((((long)nameHash)&0xffffffffL) % CVMpkg.NCLASSHASH); CVMDataType prev = null; for ( CVMDataType d = thisPkg.typeData[bucket]; d != null ; d = d.next ) { if ( d instanceof CVMClassDataType ){ CVMClassDataType c = (CVMClassDataType)d; if (c.classInPackage == classInPkg) { return c; } } prev = d; } // not there. add it. CVMClassDataType c = new CVMClassDataType( thisPkg, classInPkg ); // at end of the chain, NOT AT HEAD. if (prev == null){ thisPkg.typeData[bucket] = c; c.next = null; } else { prev.next = c; c.next = null; } return c; } static CVMArrayDataType referenceArray( int depth, int baseType ){ return referenceArray( depth, baseType, CVMpkg.nullPackage, 0 ); } static CVMArrayDataType referenceArray( int depth, CVMClassDataType d ){ return referenceArray( depth, d.typeNo, d.pkg, computeHash( d.classInPackage ) ); } static CVMArrayDataType referenceArray( int depth, int baseType, CVMpkg thisPkg, int nameHash ){ // // have a package, // do simple lookup. // make sure % is unsigned! int bucket = (int)((((long)nameHash)&0xffffffffL) % CVMpkg.NCLASSHASH); for ( CVMDataType d = thisPkg.typeData[bucket]; d != null ; d = d.next ) { if ( d instanceof CVMArrayDataType ){ CVMArrayDataType a = (CVMArrayDataType)d; if ( a.depth == depth && a.baseType == baseType ) return a; } } // not there. add it. CVMArrayDataType a = new CVMArrayDataType( depth, baseType ); // at end... a.next = thisPkg.typeData[bucket]; thisPkg.typeData[bucket] = a; return a; } public static int CVMtypeArrayDepth( int t ){ if (!isBigArray(t)){ return t>>CVMtypeArrayShift; } CVMArrayDataType d = (CVMArrayDataType)(dataTypes.elementAt( t&CVMtypeBasetypeMask)); return d.depth; } public static int CVMtypeArrayBasetype( int t ){ if (!isBigArray(t) ){ return t&CVMtypeBasetypeMask; } CVMArrayDataType d = (CVMArrayDataType)(dataTypes.elementAt( t&CVMtypeBasetypeMask)); return d.baseType; } public static int parseSignature( String sig ){ int sigLength = sig.length(); int sigIndex = 0; int arrayDepth = 0; int baseType = 0; CVMClassDataType d = null; while ( (sigIndex<sigLength) && (sig.charAt(sigIndex)==SIGC_ARRAY) ){ sigIndex += 1; arrayDepth += 1; } if ( sigIndex >= sigLength ) return CVM_T_ERROR; switch ( sig.charAt( sigIndex++ ) ){ case SIGC_VOID: baseType = CVM_T_VOID; break; case SIGC_INT: baseType = CVM_T_INT; break; case SIGC_SHORT: baseType = CVM_T_SHORT; break; case SIGC_LONG: baseType = CVM_T_LONG; break; case SIGC_BYTE: baseType = CVM_T_BYTE; break; case SIGC_CHAR: baseType = CVM_T_CHAR; break; case SIGC_FLOAT: baseType = CVM_T_FLOAT; break; case SIGC_DOUBLE: baseType = CVM_T_DOUBLE; break; case SIGC_BOOLEAN: baseType = CVM_T_BOOLEAN; break; case SIGC_CLASS: d = referenceClass( sig.substring( sigIndex, sigLength-1) ); baseType = d.typeNo; break; default: return CVM_T_ERROR; } if ( arrayDepth <= CVMtypeMaxSmallArray ) return (arrayDepth<<CVMtypeArrayShift)+baseType; /* * Here for a deep array. */ if ( d==null ){ baseType = referenceArray( arrayDepth, baseType ).typeNo; } else { baseType = referenceArray( arrayDepth, d ).typeNo; } return CVMtypeBigArray|baseType; } /* * Take either a stripped classname (no L...;) * or an array pseudo-classname (starts with [) * Return a type cookie. */ public static int lookupClassname( String name ){ if ( name.charAt(0) == SIGC_ARRAY ) return parseSignature( name ); else return referenceClass( name ).typeNo; } }