| /* |
| * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code 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 code 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 in the LICENSE file that |
| * accompanied this code). |
| * |
| * 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| * |
| */ |
| |
| package sun.jvm.hotspot.utilities; |
| |
| import java.lang.reflect.Modifier; |
| import java.util.*; |
| import sun.jvm.hotspot.debugger.*; |
| import sun.jvm.hotspot.oops.*; |
| import sun.jvm.hotspot.runtime.*; |
| import sun.jvm.hotspot.utilities.*; |
| |
| /** |
| * ObjectReader can "deserialize" objects from debuggee. |
| * |
| * Class Loading: |
| * |
| * ObjectReader loads classes using the given class loader. If no |
| * class loader is supplied, it uses a ProcImageClassLoader, which |
| * loads classes from debuggee core or process. |
| |
| * Object creation: |
| * |
| * This class uses no-arg constructor to construct objects. But if |
| * there is no no-arg constructor in a given class, then it tries to |
| * use other constructors with 'default' values - null for object |
| * types, 0, 0.0, false etc. for primitives. If this process fails to |
| * construct an instance (because of null checking by constructor or 0 |
| * being invalid for an int arg etc.), then null is returned. While |
| * constructing complete object graph 'null' is inserted silently on |
| * failure and the deserialization continues to construct best-effort |
| * object graph. |
| * |
| * Debug messages: |
| * |
| * The flag sun.jvm.hotspot.utilities.ObjectReader.DEBUG may be set to |
| * non-null to get debug error messages and stack traces. |
| * |
| * JDK version: |
| * |
| * JDK classes are loaded by bootstrap class loader and not by the |
| * supplied class loader or ProcImageClassLoader. This may create |
| * problems if a JDK class evolves. i.e., if SA runs a JDK version |
| * different from that of the debuggee, there is a possibility of |
| * schema change. It is recommended that the matching JDK version be |
| * used to run SA for proper object deserialization. |
| * |
| */ |
| |
| public class ObjectReader { |
| |
| private static final boolean DEBUG; |
| static { |
| DEBUG = System.getProperty("sun.jvm.hotspot.utilities.ObjectReader.DEBUG") != null; |
| } |
| |
| public ObjectReader(ClassLoader cl) { |
| this.cl = cl; |
| this.oopToObjMap = new HashMap(); |
| this.fieldMap = new HashMap(); |
| } |
| |
| public ObjectReader() { |
| this(new ProcImageClassLoader()); |
| } |
| |
| static void debugPrintln(String msg) { |
| if (DEBUG) { |
| System.err.println("DEBUG>" + msg); |
| } |
| } |
| |
| static void debugPrintStackTrace(Exception exp) { |
| if (DEBUG) { |
| StackTraceElement[] els = exp.getStackTrace(); |
| for (int i = 0; i < els.length; i++) { |
| System.err.println("DEBUG>" + els[i].toString()); |
| } |
| } |
| } |
| |
| public Object readObject(Oop oop) throws ClassNotFoundException { |
| if (oop instanceof Instance) { |
| return readInstance((Instance) oop); |
| } else if (oop instanceof TypeArray){ |
| return readPrimitiveArray((TypeArray)oop); |
| } else if (oop instanceof ObjArray){ |
| return readObjectArray((ObjArray)oop); |
| } else { |
| return null; |
| } |
| } |
| |
| protected final Object getDefaultPrimitiveValue(Class clz) { |
| if (clz == Boolean.TYPE) { |
| return Boolean.FALSE; |
| } else if (clz == Character.TYPE) { |
| return new Character(' '); |
| } else if (clz == Byte.TYPE) { |
| return new Byte((byte) 0); |
| } else if (clz == Short.TYPE) { |
| return new Short((short) 0); |
| } else if (clz == Integer.TYPE) { |
| return new Integer(0); |
| } else if (clz == Long.TYPE) { |
| return new Long(0L); |
| } else if (clz == Float.TYPE) { |
| return new Float(0.0f); |
| } else if (clz == Double.TYPE) { |
| return new Double(0.0); |
| } else { |
| throw new RuntimeException("should not reach here!"); |
| } |
| } |
| |
| protected Symbol javaLangString; |
| protected Symbol javaUtilHashtableEntry; |
| protected Symbol javaUtilHashtable; |
| protected Symbol javaUtilProperties; |
| |
| protected Symbol getVMSymbol(String name) { |
| return VM.getVM().getSymbolTable().probe(name); |
| } |
| |
| protected Symbol javaLangString() { |
| if (javaLangString == null) { |
| javaLangString = getVMSymbol("java/lang/String"); |
| } |
| return javaLangString; |
| } |
| |
| protected Symbol javaUtilHashtableEntry() { |
| if (javaUtilHashtableEntry == null) { |
| javaUtilHashtableEntry = getVMSymbol("java/util/Hashtable$Entry"); |
| } |
| return javaUtilHashtableEntry; |
| } |
| |
| protected Symbol javaUtilHashtable() { |
| if (javaUtilHashtable == null) { |
| javaUtilHashtable = getVMSymbol("java/util/Hashtable"); |
| } |
| return javaUtilHashtable; |
| } |
| |
| protected Symbol javaUtilProperties() { |
| if (javaUtilProperties == null) { |
| javaUtilProperties = getVMSymbol("java/util/Properties"); |
| } |
| return javaUtilProperties; |
| } |
| |
| private void setHashtableEntry(java.util.Hashtable p, Oop oop) { |
| InstanceKlass ik = (InstanceKlass)oop.getKlass(); |
| OopField keyField = (OopField)ik.findField("key", "Ljava/lang/Object;"); |
| OopField valueField = (OopField)ik.findField("value", "Ljava/lang/Object;"); |
| OopField nextField = (OopField)ik.findField("next", "Ljava/util/Hashtable$Entry;"); |
| if (DEBUG) { |
| if (Assert.ASSERTS_ENABLED) { |
| Assert.that(ik.getName().equals(javaUtilHashtableEntry()), "Not a Hashtable$Entry?"); |
| Assert.that(keyField != null && valueField != null && nextField != null, "Invalid fields!"); |
| } |
| } |
| |
| Object key = null; |
| Object value = null; |
| Oop next = null; |
| try { |
| key = readObject(keyField.getValue(oop)); |
| value = readObject(valueField.getValue(oop)); |
| next = (Oop)nextField.getValue(oop); |
| // For Properties, should use setProperty(k, v). Since it only runs in SA |
| // using put(k, v) should be OK. |
| p.put(key, value); |
| if (next != null) { |
| setHashtableEntry(p, next); |
| } |
| } catch (ClassNotFoundException ce) { |
| if( DEBUG) { |
| debugPrintln("Class not found " + ce); |
| debugPrintStackTrace(ce); |
| } |
| } |
| } |
| |
| protected Object getHashtable(Instance oop, boolean isProperties) { |
| InstanceKlass k = (InstanceKlass)oop.getKlass(); |
| OopField tableField = (OopField)k.findField("table", "[Ljava/util/Hashtable$Entry;"); |
| if (tableField == null) { |
| debugPrintln("Could not find field of [Ljava/util/Hashtable$Entry;"); |
| return null; |
| } |
| java.util.Hashtable table = (isProperties) ? new java.util.Properties() |
| : new java.util.Hashtable(); |
| ObjArray kvs = (ObjArray)tableField.getValue(oop); |
| long size = kvs.getLength(); |
| debugPrintln("Hashtable$Entry Size = " + size); |
| for (long i=0; i<size; i++) { |
| Oop entry = kvs.getObjAt(i); |
| if (entry != null && entry.isInstance()) { |
| setHashtableEntry(table, entry); |
| } |
| } |
| return table; |
| } |
| |
| public Object readInstance(Instance oop) throws ClassNotFoundException { |
| Object result = getFromObjTable(oop); |
| if (result == null) { |
| InstanceKlass kls = (InstanceKlass) oop.getKlass(); |
| // Handle java.lang.String instances differently. As part of JSR-133, fields of immutable |
| // classes have been made final. The algorithm below will not be able to read Strings from |
| // debuggee (can't use reflection to set final fields). But, need to read Strings is very |
| // important. |
| // Same for Hashtable, key and hash are final, could not be set in the algorithm too. |
| // FIXME: need a framework to handle many other special cases. |
| if (kls.getName().equals(javaLangString())) { |
| return OopUtilities.stringOopToString(oop); |
| } |
| |
| if (kls.getName().equals(javaUtilHashtable())) { |
| return getHashtable(oop, false); |
| } |
| |
| if (kls.getName().equals(javaUtilProperties())) { |
| return getHashtable(oop, true); |
| } |
| |
| Class clz = readClass(kls); |
| try { |
| result = clz.newInstance(); |
| } catch (Exception ex) { |
| // no-arg constructor failed to create object. Let us try |
| // to call constructors one-by-one with default arguments |
| // (null for objects, 0/0.0 etc. for primitives) till we |
| // succeed or fail on all constructors. |
| |
| java.lang.reflect.Constructor[] ctrs = clz.getDeclaredConstructors(); |
| for (int n = 0; n < ctrs.length; n++) { |
| java.lang.reflect.Constructor c = ctrs[n]; |
| Class[] paramTypes = c.getParameterTypes(); |
| Object[] params = new Object[paramTypes.length]; |
| for (int i = 0; i < params.length; i++) { |
| if (paramTypes[i].isPrimitive()) { |
| params[i] = getDefaultPrimitiveValue(paramTypes[i]); |
| } |
| } |
| try { |
| c.setAccessible(true); |
| result = c.newInstance(params); |
| break; |
| } catch (Exception exp) { |
| if (DEBUG) { |
| debugPrintln("Can't create object using " + c); |
| debugPrintStackTrace(exp); |
| } |
| } |
| } |
| } |
| |
| if (result != null) { |
| putIntoObjTable(oop, result); |
| oop.iterate(new FieldSetter(result), false); |
| } |
| } |
| return result; |
| } |
| |
| public Object readPrimitiveArray(final TypeArray array) { |
| |
| Object result = getFromObjTable(array); |
| if (result == null) { |
| int length = (int) array.getLength(); |
| TypeArrayKlass klass = (TypeArrayKlass) array.getKlass(); |
| int type = (int) klass.getElementType(); |
| switch (type) { |
| case TypeArrayKlass.T_BOOLEAN: { |
| final boolean[] arrayObj = new boolean[length]; |
| array.iterate(new DefaultOopVisitor() { |
| public void doBoolean(BooleanField field, boolean isVMField) { |
| IndexableFieldIdentifier ifd = (IndexableFieldIdentifier) field.getID(); |
| arrayObj[ifd.getIndex()] = field.getValue(array); |
| } |
| }, false); |
| result = arrayObj; |
| } |
| break; |
| |
| case TypeArrayKlass.T_CHAR: { |
| final char[] arrayObj = new char[length]; |
| array.iterate(new DefaultOopVisitor() { |
| public void doChar(CharField field, boolean isVMField) { |
| IndexableFieldIdentifier ifd = (IndexableFieldIdentifier) field.getID(); |
| arrayObj[ifd.getIndex()] = field.getValue(array); |
| } |
| }, false); |
| result = arrayObj; |
| } |
| break; |
| |
| case TypeArrayKlass.T_FLOAT: { |
| final float[] arrayObj = new float[length]; |
| array.iterate(new DefaultOopVisitor() { |
| public void doFloat(FloatField field, boolean isVMField) { |
| IndexableFieldIdentifier ifd = (IndexableFieldIdentifier) field.getID(); |
| arrayObj[ifd.getIndex()] = field.getValue(array); |
| } |
| }, false); |
| result = arrayObj; |
| } |
| break; |
| |
| case TypeArrayKlass.T_DOUBLE: { |
| final double[] arrayObj = new double[length]; |
| array.iterate(new DefaultOopVisitor() { |
| public void doDouble(DoubleField field, boolean isVMField) { |
| IndexableFieldIdentifier ifd = (IndexableFieldIdentifier) field.getID(); |
| arrayObj[ifd.getIndex()] = field.getValue(array); |
| } |
| }, false); |
| result = arrayObj; |
| } |
| break; |
| |
| case TypeArrayKlass.T_BYTE: { |
| final byte[] arrayObj = new byte[length]; |
| array.iterate(new DefaultOopVisitor() { |
| public void doByte(ByteField field, boolean isVMField) { |
| IndexableFieldIdentifier ifd = (IndexableFieldIdentifier) field.getID(); |
| arrayObj[ifd.getIndex()] = field.getValue(array); |
| } |
| }, false); |
| result = arrayObj; |
| } |
| break; |
| |
| case TypeArrayKlass.T_SHORT: { |
| final short[] arrayObj = new short[length]; |
| array.iterate(new DefaultOopVisitor() { |
| public void doShort(ShortField field, boolean isVMField) { |
| IndexableFieldIdentifier ifd = (IndexableFieldIdentifier) field.getID(); |
| arrayObj[ifd.getIndex()] = field.getValue(array); |
| } |
| }, false); |
| result = arrayObj; |
| } |
| break; |
| |
| case TypeArrayKlass.T_INT: { |
| final int[] arrayObj = new int[length]; |
| array.iterate(new DefaultOopVisitor() { |
| public void doInt(IntField field, boolean isVMField) { |
| IndexableFieldIdentifier ifd = (IndexableFieldIdentifier) field.getID(); |
| arrayObj[ifd.getIndex()] = field.getValue(array); |
| } |
| }, false); |
| result = arrayObj; |
| } |
| break; |
| |
| case TypeArrayKlass.T_LONG: { |
| final long[] arrayObj = new long[length]; |
| array.iterate(new DefaultOopVisitor() { |
| public void doLong(LongField field, boolean isVMField) { |
| IndexableFieldIdentifier ifd = (IndexableFieldIdentifier) field.getID(); |
| arrayObj[ifd.getIndex()] = field.getValue(array); |
| } |
| }, false); |
| result = arrayObj; |
| } |
| break; |
| |
| default: |
| throw new RuntimeException("should not reach here!"); |
| } |
| |
| putIntoObjTable(array, result); |
| } |
| return result; |
| } |
| |
| protected final boolean isRobust(OopHandle handle) { |
| return RobustOopDeterminator.oopLooksValid(handle); |
| } |
| |
| public Object readObjectArray(final ObjArray array) throws ClassNotFoundException { |
| Object result = getFromObjTable(array); |
| if (result == null) { |
| int length = (int) array.getLength(); |
| ObjArrayKlass klass = (ObjArrayKlass) array.getKlass(); |
| Klass bottomKls = klass.getBottomKlass(); |
| Class bottomCls = null; |
| final int dimension = (int) klass.getDimension(); |
| int[] dimArray = null; |
| if (bottomKls instanceof InstanceKlass) { |
| bottomCls = readClass((InstanceKlass) bottomKls); |
| dimArray = new int[dimension]; |
| } else { // instanceof TypeArrayKlass |
| TypeArrayKlass botKls = (TypeArrayKlass) bottomKls; |
| dimArray = new int[dimension -1]; |
| } |
| // initialize the length |
| dimArray[0] = length; |
| final Object[] arrayObj = (Object[]) java.lang.reflect.Array.newInstance(bottomCls, dimArray); |
| putIntoObjTable(array, arrayObj); |
| result = arrayObj; |
| array.iterate(new DefaultOopVisitor() { |
| public void doOop(OopField field, boolean isVMField) { |
| OopHandle handle = field.getValueAsOopHandle(getObj()); |
| if (! isRobust(handle)) { |
| return; |
| } |
| |
| IndexableFieldIdentifier ifd = (IndexableFieldIdentifier) field.getID(); |
| try { |
| arrayObj[ifd.getIndex()] = readObject(field.getValue(getObj())); |
| } catch (Exception e) { |
| if (DEBUG) { |
| debugPrintln("Array element set failed for " + ifd); |
| debugPrintStackTrace(e); |
| } |
| } |
| } |
| }, false); |
| } |
| return result; |
| } |
| |
| protected class FieldSetter extends DefaultOopVisitor { |
| protected Object obj; |
| |
| public FieldSetter(Object obj) { |
| this.obj = obj; |
| } |
| |
| private void printFieldSetError(java.lang.reflect.Field f, Exception ex) { |
| if (DEBUG) { |
| if (f != null) debugPrintln("Field set failed for " + f); |
| debugPrintStackTrace(ex); |
| } |
| } |
| |
| // Callback methods for each field type in an object |
| public void doOop(OopField field, boolean isVMField) { |
| OopHandle handle = field.getValueAsOopHandle(getObj()); |
| if (! isRobust(handle) ) { |
| return; |
| } |
| |
| java.lang.reflect.Field f = null; |
| try { |
| f = readField(field); |
| if (Modifier.isFinal(f.getModifiers())) return; |
| f.setAccessible(true); |
| f.set(obj, readObject(field.getValue(getObj()))); |
| } catch (Exception ex) { |
| printFieldSetError(f, ex); |
| } |
| } |
| |
| public void doByte(ByteField field, boolean isVMField) { |
| java.lang.reflect.Field f = null; |
| try { |
| f = readField(field); |
| if (Modifier.isFinal(f.getModifiers())) return; |
| f.setAccessible(true); |
| f.setByte(obj, field.getValue(getObj())); |
| } catch (Exception ex) { |
| printFieldSetError(f, ex); |
| } |
| } |
| |
| public void doChar(CharField field, boolean isVMField) { |
| java.lang.reflect.Field f = null; |
| try { |
| f = readField(field); |
| if (Modifier.isFinal(f.getModifiers())) return; |
| f.setAccessible(true); |
| f.setChar(obj, field.getValue(getObj())); |
| } catch (Exception ex) { |
| printFieldSetError(f, ex); |
| } |
| } |
| |
| public void doBoolean(BooleanField field, boolean isVMField) { |
| java.lang.reflect.Field f = null; |
| try { |
| f = readField(field); |
| if (Modifier.isFinal(f.getModifiers())) return; |
| f.setAccessible(true); |
| f.setBoolean(obj, field.getValue(getObj())); |
| } catch (Exception ex) { |
| printFieldSetError(f, ex); |
| } |
| } |
| |
| public void doShort(ShortField field, boolean isVMField) { |
| java.lang.reflect.Field f = null; |
| try { |
| f = readField(field); |
| if (Modifier.isFinal(f.getModifiers())) return; |
| f.setAccessible(true); |
| f.setShort(obj, field.getValue(getObj())); |
| } catch (Exception ex) { |
| printFieldSetError(f, ex); |
| } |
| } |
| |
| public void doInt(IntField field, boolean isVMField) { |
| java.lang.reflect.Field f = null; |
| try { |
| f = readField(field); |
| if (Modifier.isFinal(f.getModifiers())) return; |
| f.setAccessible(true); |
| f.setInt(obj, field.getValue(getObj())); |
| } catch (Exception ex) { |
| printFieldSetError(f, ex); |
| } |
| } |
| |
| public void doLong(LongField field, boolean isVMField) { |
| java.lang.reflect.Field f = null; |
| try { |
| f = readField(field); |
| if (Modifier.isFinal(f.getModifiers())) return; |
| f.setAccessible(true); |
| f.setLong(obj, field.getValue(getObj())); |
| } catch (Exception ex) { |
| printFieldSetError(f, ex); |
| } |
| } |
| |
| public void doFloat(FloatField field, boolean isVMField) { |
| java.lang.reflect.Field f = null; |
| try { |
| f = readField(field); |
| if (Modifier.isFinal(f.getModifiers())) return; |
| f.setAccessible(true); |
| f.setFloat(obj, field.getValue(getObj())); |
| } catch (Exception ex) { |
| printFieldSetError(f, ex); |
| } |
| } |
| |
| public void doDouble(DoubleField field, boolean isVMField) { |
| java.lang.reflect.Field f = null; |
| try { |
| f = readField(field); |
| if (Modifier.isFinal(f.getModifiers())) return; |
| f.setAccessible(true); |
| f.setDouble(obj, field.getValue(getObj())); |
| } catch (Exception ex) { |
| printFieldSetError(f, ex); |
| } |
| } |
| |
| public void doCInt(CIntField field, boolean isVMField) { |
| throw new RuntimeException("should not reach here!"); |
| } |
| } |
| |
| public Class readClass(InstanceKlass kls) throws ClassNotFoundException { |
| Class cls = (Class) getFromObjTable(kls); |
| if (cls == null) { |
| cls = Class.forName(kls.getName().asString().replace('/', '.'), true, cl); |
| putIntoObjTable(kls, cls); |
| } |
| return cls; |
| } |
| |
| public Object readMethodOrConstructor(sun.jvm.hotspot.oops.Method m) |
| throws NoSuchMethodException, ClassNotFoundException { |
| String name = m.getName().asString(); |
| if (name.equals("<init>")) { |
| return readConstructor(m); |
| } else { |
| return readMethod(m); |
| } |
| } |
| |
| public java.lang.reflect.Method readMethod(sun.jvm.hotspot.oops.Method m) |
| throws NoSuchMethodException, ClassNotFoundException { |
| java.lang.reflect.Method result = (java.lang.reflect.Method) getFromObjTable(m); |
| if (result == null) { |
| Class clz = readClass((InstanceKlass)m.getMethodHolder()); |
| String name = m.getName().asString(); |
| Class[] paramTypes = getParamTypes(m.getSignature()); |
| result = clz.getMethod(name, paramTypes); |
| putIntoObjTable(m, result); |
| } |
| return result; |
| } |
| |
| public java.lang.reflect.Constructor readConstructor(sun.jvm.hotspot.oops.Method m) |
| throws NoSuchMethodException, ClassNotFoundException { |
| java.lang.reflect.Constructor result = (java.lang.reflect.Constructor) getFromObjTable(m); |
| if (result == null) { |
| Class clz = readClass((InstanceKlass)m.getMethodHolder()); |
| String name = m.getName().asString(); |
| Class[] paramTypes = getParamTypes(m.getSignature()); |
| result = clz.getDeclaredConstructor(paramTypes); |
| putIntoObjTable(m, result); |
| } |
| return result; |
| } |
| |
| public java.lang.reflect.Field readField(sun.jvm.hotspot.oops.Field f) |
| throws NoSuchFieldException, ClassNotFoundException { |
| java.lang.reflect.Field result = (java.lang.reflect.Field) fieldMap.get(f); |
| if (result == null) { |
| FieldIdentifier fieldId = f.getID(); |
| Class clz = readClass((InstanceKlass) f.getFieldHolder()); |
| String name = fieldId.getName(); |
| try { |
| result = clz.getField(name); |
| } catch (NoSuchFieldException nsfe) { |
| result = clz.getDeclaredField(name); |
| } |
| fieldMap.put(f, result); |
| } |
| return result; |
| } |
| |
| protected final ClassLoader cl; |
| protected Map oopToObjMap; // Map<Oop, Object> |
| protected Map fieldMap; // Map<sun.jvm.hotspot.oops.Field, java.lang.reflect.Field> |
| |
| protected void putIntoObjTable(Oop oop, Object obj) { |
| oopToObjMap.put(oop, obj); |
| } |
| |
| protected Object getFromObjTable(Oop oop) { |
| return oopToObjMap.get(oop); |
| } |
| |
| protected void putIntoObjTable(Metadata oop, Object obj) { |
| oopToObjMap.put(oop, obj); |
| } |
| |
| protected Object getFromObjTable(Metadata oop) { |
| return oopToObjMap.get(oop); |
| } |
| |
| protected class SignatureParser extends SignatureIterator { |
| protected Vector tmp = new Vector(); // Vector<Class> |
| |
| public SignatureParser(Symbol s) { |
| super(s); |
| } |
| |
| public void doBool () { tmp.add(Boolean.TYPE); } |
| public void doChar () { tmp.add(Character.TYPE); } |
| public void doFloat () { tmp.add(Float.TYPE); } |
| public void doDouble() { tmp.add(Double.TYPE); } |
| public void doByte () { tmp.add(Byte.TYPE); } |
| public void doShort () { tmp.add(Short.TYPE); } |
| public void doInt () { tmp.add(Integer.TYPE); } |
| public void doLong () { tmp.add(Long.TYPE); } |
| public void doVoid () { |
| if(isReturnType()) { |
| tmp.add(Void.TYPE); |
| } else { |
| throw new RuntimeException("should not reach here"); |
| } |
| } |
| |
| public void doObject(int begin, int end) { |
| tmp.add(getClass(begin, end)); |
| } |
| |
| public void doArray (int begin, int end) { |
| int inner = arrayInnerBegin(begin); |
| Class elemCls = null; |
| switch (_signature.getByteAt(inner)) { |
| case 'B': elemCls = Boolean.TYPE; break; |
| case 'C': elemCls = Character.TYPE; break; |
| case 'D': elemCls = Double.TYPE; break; |
| case 'F': elemCls = Float.TYPE; break; |
| case 'I': elemCls = Integer.TYPE; break; |
| case 'J': elemCls = Long.TYPE; break; |
| case 'S': elemCls = Short.TYPE; break; |
| case 'Z': elemCls = Boolean.TYPE; break; |
| case 'L': elemCls = getClass(inner + 1, end); break; |
| default: break; |
| } |
| |
| int dimension = inner - begin; |
| // create 0 x 0 ... array and get class from that |
| int[] dimArray = new int[dimension]; |
| tmp.add(java.lang.reflect.Array.newInstance(elemCls, dimArray).getClass()); |
| } |
| |
| protected Class getClass(int begin, int end) { |
| String className = getClassName(begin, end); |
| try { |
| return Class.forName(className, true, cl); |
| } catch (Exception e) { |
| if (DEBUG) { |
| debugPrintln("Can't load class " + className); |
| } |
| throw new RuntimeException(e); |
| } |
| } |
| |
| protected String getClassName(int begin, int end) { |
| StringBuffer buf = new StringBuffer(); |
| for (int i = begin; i < end; i++) { |
| char c = (char) (_signature.getByteAt(i) & 0xFF); |
| if (c == '/') { |
| buf.append('.'); |
| } else { |
| buf.append(c); |
| } |
| } |
| return buf.toString(); |
| } |
| |
| protected int arrayInnerBegin(int begin) { |
| while (_signature.getByteAt(begin) == '[') { |
| ++begin; |
| } |
| return begin; |
| } |
| |
| public int getNumParams() { |
| return tmp.size(); |
| } |
| |
| public Enumeration getParamTypes() { |
| return tmp.elements(); |
| } |
| } |
| |
| protected Class[] getParamTypes(Symbol signature) { |
| SignatureParser sp = new SignatureParser(signature); |
| sp.iterateParameters(); |
| Class result[] = new Class[sp.getNumParams()]; |
| Enumeration e = sp.getParamTypes(); |
| int i = 0; |
| while (e.hasMoreElements()) { |
| result[i] = (Class) e.nextElement(); |
| i++; |
| } |
| return result; |
| } |
| } |