| 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 */  | 
 | 
 | 
 | 
 | 
 | 
/*  | 
 | 
 * The Original Code is HAT. The Initial Developer of the  | 
 | 
 * Original Code is Bill Foote, with contributions from others  | 
 | 
 * at JavaSoft/Sun.  | 
 | 
 */  | 
 | 
 | 
 | 
package com.sun.tools.hat.internal.model;  | 
 | 
 | 
 | 
import com.sun.tools.hat.internal.parser.ReadBuffer;  | 
 | 
import java.io.IOException;  | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 */  | 
 | 
public class JavaValueArray extends JavaLazyReadObject  | 
 | 
                 implements ArrayTypeCodes { | 
 | 
 | 
 | 
    private static String arrayTypeName(byte sig) { | 
 | 
        switch (sig) { | 
 | 
            case 'B':  | 
 | 
                return "byte[]";  | 
 | 
            case 'Z':  | 
 | 
                return "boolean[]";  | 
 | 
            case 'C':  | 
 | 
                return "char[]";  | 
 | 
            case 'S':  | 
 | 
                return "short[]";  | 
 | 
            case 'I':  | 
 | 
                return "int[]";  | 
 | 
            case 'F':  | 
 | 
                return "float[]";  | 
 | 
            case 'J':  | 
 | 
                return "long[]";  | 
 | 
            case 'D':  | 
 | 
                return "double[]";  | 
 | 
            default:  | 
 | 
                throw new RuntimeException("invalid array element sig: " + sig); | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    private static int elementSize(byte type) { | 
 | 
        switch (type) { | 
 | 
            case T_BYTE:  | 
 | 
            case T_BOOLEAN:  | 
 | 
                return 1;  | 
 | 
            case T_CHAR:  | 
 | 
            case T_SHORT:  | 
 | 
                return 2;  | 
 | 
            case T_INT:  | 
 | 
            case T_FLOAT:  | 
 | 
                return 4;  | 
 | 
            case T_LONG:  | 
 | 
            case T_DOUBLE:  | 
 | 
                return 8;  | 
 | 
            default:  | 
 | 
                throw new RuntimeException("invalid array element type: " + type); | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    protected final int readValueLength() throws IOException { | 
 | 
        JavaClass cl = getClazz();  | 
 | 
        ReadBuffer buf = cl.getReadBuffer();  | 
 | 
        int idSize = cl.getIdentifierSize();  | 
 | 
        long offset = getOffset() + idSize + 4;  | 
 | 
          | 
 | 
        int len = buf.getInt(offset);  | 
 | 
          | 
 | 
        byte type = buf.getByte(offset + 4);  | 
 | 
        return len * elementSize(type);  | 
 | 
    }  | 
 | 
 | 
 | 
    protected final byte[] readValue() throws IOException { | 
 | 
        JavaClass cl = getClazz();  | 
 | 
        ReadBuffer buf = cl.getReadBuffer();  | 
 | 
        int idSize = cl.getIdentifierSize();  | 
 | 
        long offset = getOffset() + idSize + 4;  | 
 | 
          | 
 | 
        int length = buf.getInt(offset);  | 
 | 
          | 
 | 
        byte type = buf.getByte(offset + 4);  | 
 | 
        if (length == 0) { | 
 | 
            return Snapshot.EMPTY_BYTE_ARRAY;  | 
 | 
        } else { | 
 | 
            length *= elementSize(type);  | 
 | 
            byte[] res = new byte[length];  | 
 | 
            buf.get(offset + 5, res);  | 
 | 
            return res;  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
    private JavaClass clazz;  | 
 | 
 | 
 | 
    // This field contains elementSignature byte and  | 
 | 
    // divider to be used to calculate length. Note that  | 
 | 
    // length of content byte[] is not same as array length.  | 
 | 
      | 
 | 
    private int data;  | 
 | 
 | 
 | 
      | 
 | 
    private static final int SIGNATURE_MASK = 0x0FF;  | 
 | 
 | 
 | 
      | 
 | 
    private static final int LENGTH_DIVIDER_MASK = 0x0FF00;  | 
 | 
 | 
 | 
      | 
 | 
    private static final int LENGTH_DIVIDER_SHIFT = 8;  | 
 | 
 | 
 | 
    public JavaValueArray(byte elementSignature, long offset) { | 
 | 
        super(offset);  | 
 | 
        this.data = (elementSignature & SIGNATURE_MASK);  | 
 | 
    }  | 
 | 
 | 
 | 
    public JavaClass getClazz() { | 
 | 
        return clazz;  | 
 | 
    }  | 
 | 
 | 
 | 
    public void visitReferencedObjects(JavaHeapObjectVisitor v) { | 
 | 
        super.visitReferencedObjects(v);  | 
 | 
    }  | 
 | 
 | 
 | 
    public void resolve(Snapshot snapshot) { | 
 | 
        if (clazz instanceof JavaClass) { | 
 | 
            return;  | 
 | 
        }  | 
 | 
        byte elementSig = getElementType();  | 
 | 
        clazz = snapshot.findClass(arrayTypeName(elementSig));  | 
 | 
        if (clazz == null) { | 
 | 
            clazz = snapshot.getArrayClass("" + ((char) elementSig)); | 
 | 
        }  | 
 | 
        getClazz().addInstance(this);  | 
 | 
        super.resolve(snapshot);  | 
 | 
    }  | 
 | 
 | 
 | 
    public int getLength() { | 
 | 
        int divider = (data & LENGTH_DIVIDER_MASK) >>> LENGTH_DIVIDER_SHIFT;  | 
 | 
        if (divider == 0) { | 
 | 
            byte elementSignature = getElementType();  | 
 | 
            switch (elementSignature) { | 
 | 
            case 'B':  | 
 | 
            case 'Z':  | 
 | 
                divider = 1;  | 
 | 
                break;  | 
 | 
            case 'C':  | 
 | 
            case 'S':  | 
 | 
                divider = 2;  | 
 | 
                break;  | 
 | 
            case 'I':  | 
 | 
            case 'F':  | 
 | 
                divider = 4;  | 
 | 
                break;  | 
 | 
            case 'J':  | 
 | 
            case 'D':  | 
 | 
                divider = 8;  | 
 | 
                break;  | 
 | 
            default:  | 
 | 
                throw new RuntimeException("unknown primitive type: " + | 
 | 
                                elementSignature);  | 
 | 
            }  | 
 | 
            data |= (divider << LENGTH_DIVIDER_SHIFT);  | 
 | 
        }  | 
 | 
        return (getValueLength() / divider);  | 
 | 
    }  | 
 | 
 | 
 | 
    public Object getElements() { | 
 | 
        final int len = getLength();  | 
 | 
        final byte et = getElementType();  | 
 | 
        byte[] data = getValue();  | 
 | 
        int index = 0;  | 
 | 
        switch (et) { | 
 | 
            case 'Z': { | 
 | 
                boolean[] res = new boolean[len];  | 
 | 
                for (int i = 0; i < len; i++) { | 
 | 
                    res[i] = booleanAt(index, data);  | 
 | 
                    index++;  | 
 | 
                }  | 
 | 
                return res;  | 
 | 
            }  | 
 | 
            case 'B': { | 
 | 
                byte[] res = new byte[len];  | 
 | 
                for (int i = 0; i < len; i++) { | 
 | 
                    res[i] = byteAt(index, data);  | 
 | 
                    index++;  | 
 | 
                }  | 
 | 
                return res;  | 
 | 
            }  | 
 | 
            case 'C': { | 
 | 
                char[] res = new char[len];  | 
 | 
                for (int i = 0; i < len; i++) { | 
 | 
                    res[i] = charAt(index, data);  | 
 | 
                    index += 2;  | 
 | 
                }  | 
 | 
                return res;  | 
 | 
            }  | 
 | 
            case 'S': { | 
 | 
                short[] res = new short[len];  | 
 | 
                for (int i = 0; i < len; i++) { | 
 | 
                    res[i] = shortAt(index, data);  | 
 | 
                    index += 2;  | 
 | 
                }  | 
 | 
                return res;  | 
 | 
            }  | 
 | 
            case 'I': { | 
 | 
                int[] res = new int[len];  | 
 | 
                for (int i = 0; i < len; i++) { | 
 | 
                    res[i] = intAt(index, data);  | 
 | 
                    index += 4;  | 
 | 
                }  | 
 | 
                return res;  | 
 | 
            }  | 
 | 
            case 'J': { | 
 | 
                long[] res = new long[len];  | 
 | 
                for (int i = 0; i < len; i++) { | 
 | 
                    res[i] = longAt(index, data);  | 
 | 
                    index += 8;  | 
 | 
                }  | 
 | 
                return res;  | 
 | 
            }  | 
 | 
            case 'F': { | 
 | 
                float[] res = new float[len];  | 
 | 
                for (int i = 0; i < len; i++) { | 
 | 
                    res[i] = floatAt(index, data);  | 
 | 
                    index += 4;  | 
 | 
                }  | 
 | 
                return res;  | 
 | 
            }  | 
 | 
            case 'D': { | 
 | 
                double[] res = new double[len];  | 
 | 
                for (int i = 0; i < len; i++) { | 
 | 
                    res[i] = doubleAt(index, data);  | 
 | 
                    index += 8;  | 
 | 
                }  | 
 | 
                return res;  | 
 | 
            }  | 
 | 
            default: { | 
 | 
                throw new RuntimeException("unknown primitive type?"); | 
 | 
            }  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    public byte getElementType() { | 
 | 
        return (byte) (data & SIGNATURE_MASK);  | 
 | 
    }  | 
 | 
 | 
 | 
    private void checkIndex(int index) { | 
 | 
        if (index < 0 || index >= getLength()) { | 
 | 
            throw new ArrayIndexOutOfBoundsException(index);  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    private void requireType(char type) { | 
 | 
        if (getElementType() != type) { | 
 | 
            throw new RuntimeException("not of type : " + type); | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    public boolean getBooleanAt(int index) { | 
 | 
        checkIndex(index);  | 
 | 
        requireType('Z'); | 
 | 
        return booleanAt(index, getValue());  | 
 | 
    }  | 
 | 
 | 
 | 
    public byte getByteAt(int index) { | 
 | 
        checkIndex(index);  | 
 | 
        requireType('B'); | 
 | 
        return byteAt(index, getValue());  | 
 | 
    }  | 
 | 
 | 
 | 
    public char getCharAt(int index) { | 
 | 
        checkIndex(index);  | 
 | 
        requireType('C'); | 
 | 
        return charAt(index << 1, getValue());  | 
 | 
    }  | 
 | 
 | 
 | 
    public short getShortAt(int index) { | 
 | 
        checkIndex(index);  | 
 | 
        requireType('S'); | 
 | 
        return shortAt(index << 1, getValue());  | 
 | 
    }  | 
 | 
 | 
 | 
    public int getIntAt(int index) { | 
 | 
        checkIndex(index);  | 
 | 
        requireType('I'); | 
 | 
        return intAt(index << 2, getValue());  | 
 | 
    }  | 
 | 
 | 
 | 
    public long getLongAt(int index) { | 
 | 
        checkIndex(index);  | 
 | 
        requireType('J'); | 
 | 
        return longAt(index << 3, getValue());  | 
 | 
    }  | 
 | 
 | 
 | 
    public float getFloatAt(int index) { | 
 | 
        checkIndex(index);  | 
 | 
        requireType('F'); | 
 | 
        return floatAt(index << 2, getValue());  | 
 | 
    }  | 
 | 
 | 
 | 
    public double getDoubleAt(int index) { | 
 | 
        checkIndex(index);  | 
 | 
        requireType('D'); | 
 | 
        return doubleAt(index << 3, getValue());  | 
 | 
    }  | 
 | 
 | 
 | 
    public String valueString() { | 
 | 
        return valueString(true);  | 
 | 
    }  | 
 | 
 | 
 | 
    public String valueString(boolean bigLimit) { | 
 | 
          | 
 | 
        StringBuffer result;  | 
 | 
        byte[] value = getValue();  | 
 | 
        int max = value.length;  | 
 | 
        byte elementSignature = getElementType();  | 
 | 
        if (elementSignature == 'C')  { | 
 | 
            result = new StringBuffer();  | 
 | 
            for (int i = 0; i < value.length; ) { | 
 | 
                char val = charAt(i, value);  | 
 | 
                result.append(val);  | 
 | 
                i += 2;  | 
 | 
            }  | 
 | 
        } else { | 
 | 
            int limit = 8;  | 
 | 
            if (bigLimit) { | 
 | 
                limit = 1000;  | 
 | 
            }  | 
 | 
            result = new StringBuffer("{"); | 
 | 
            int num = 0;  | 
 | 
            for (int i = 0; i < value.length; ) { | 
 | 
                if (num > 0) { | 
 | 
                    result.append(", "); | 
 | 
                }  | 
 | 
                if (num >= limit) { | 
 | 
                    result.append("... "); | 
 | 
                    break;  | 
 | 
                }  | 
 | 
                num++;  | 
 | 
                switch (elementSignature) { | 
 | 
                    case 'Z': { | 
 | 
                        boolean val = booleanAt(i, value);  | 
 | 
                        if (val) { | 
 | 
                            result.append("true"); | 
 | 
                        } else { | 
 | 
                            result.append("false"); | 
 | 
                        }  | 
 | 
                        i++;  | 
 | 
                        break;  | 
 | 
                    }  | 
 | 
                    case 'B': { | 
 | 
                        int val = 0xFF & byteAt(i, value);  | 
 | 
                        result.append("0x" + Integer.toString(val, 16)); | 
 | 
                        i++;  | 
 | 
                        break;  | 
 | 
                    }  | 
 | 
                    case 'S': { | 
 | 
                        short val = shortAt(i, value);  | 
 | 
                        i += 2;  | 
 | 
                        result.append("" + val); | 
 | 
                        break;  | 
 | 
                    }  | 
 | 
                    case 'I': { | 
 | 
                        int val = intAt(i, value);  | 
 | 
                        i += 4;  | 
 | 
                        result.append("" + val); | 
 | 
                        break;  | 
 | 
                    }  | 
 | 
                    case 'J': {          | 
 | 
                        long val = longAt(i, value);  | 
 | 
                        result.append("" + val); | 
 | 
                        i += 8;  | 
 | 
                        break;  | 
 | 
                    }  | 
 | 
                    case 'F': { | 
 | 
                        float val = floatAt(i, value);  | 
 | 
                        result.append("" + val); | 
 | 
                        i += 4;  | 
 | 
                        break;  | 
 | 
                    }  | 
 | 
                    case 'D': {          | 
 | 
                        double val = doubleAt(i, value);  | 
 | 
                        result.append("" + val); | 
 | 
                        i += 8;  | 
 | 
                        break;  | 
 | 
                    }  | 
 | 
                    default: { | 
 | 
                        throw new RuntimeException("unknown primitive type?"); | 
 | 
                    }  | 
 | 
                }  | 
 | 
            }  | 
 | 
            result.append("}"); | 
 | 
        }  | 
 | 
        return result.toString();  | 
 | 
    }  | 
 | 
 | 
 | 
}  |