433 lines · 13.2 KB · Java
RawDownload
/* * Copyright (c) 1997, 2008, 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.  Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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. */  /* * 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; /** * An array of values, that is, an array of ints, boolean, floats or the like. * * @author      Bill Foote */public class JavaValueArray extends JavaLazyReadObject                /*imports*/ 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);        }    }     /*     * Java primitive array record (HPROF_GC_PRIM_ARRAY_DUMP) looks     * as below:     *     *    object ID     *    stack trace serial number (int)     *    length of the instance data (int)     *    element type (byte)     *    array data     */    protected final int readValueLength() throws IOException {        JavaClass cl = getClazz();        ReadBuffer buf = cl.getReadBuffer();        int idSize = cl.getIdentifierSize();        long offset = getOffset() + idSize + 4;        // length of the array        int len = buf.getInt(offset);        // typecode of array element type        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;        // length of the array        int length = buf.getInt(offset);        // typecode of array element type        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;        }    }     // JavaClass set only after resolve.    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.    // Actual array length is (byte[].length / divider)    private int data;     // First 8 bits of data is used for element signature    private static final int SIGNATURE_MASK = 0x0FF;     // Next 8 bits of data is used for length divider    private static final int LENGTH_DIVIDER_MASK = 0x0FF00;     // Number of bits to shift to get length divider    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) {        // Char arrays deserve special treatment        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                        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                        double val = doubleAt(i, value);                        result.append("" + val);                        i += 8;                        break;                    }                    default: {                        throw new RuntimeException("unknown primitive type?");                    }                }            }            result.append("}");        }        return result.toString();    } }