--- /dev/null 2019-02-07 20:54:51.336000000 +0300 +++ new/test/lib/jdk/test/lib/hprof/model/JavaValueArray.java 2019-02-08 18:34:08.290949719 +0300 @@ -0,0 +1,354 @@ +/* + * Copyright (c) 1997, 2017, 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 jdk.test.lib.hprof.model; + +import jdk.test.lib.hprof.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) + * number of elements (int) + * element type (byte) + * array data + */ + @Override + protected final long readValueLength() throws IOException { + long offset = getOffset() + idSize() + 4; + // length of the array in elements + long len = buf().getInt(offset); + // byte length of array + return len * elementSize(getElementType()); + } + + private long dataStartOffset() { + return getOffset() + idSize() + 4 + 4 + 1; + } + + + @Override + protected final JavaThing[] readValue() throws IOException { + int len = getLength(); + long offset = dataStartOffset(); + + JavaThing[] res = new JavaThing[len]; + synchronized (buf()) { + switch (getElementType()) { + case 'Z': { + for (int i = 0; i < len; i++) { + res[i] = new JavaBoolean(booleanAt(offset)); + offset += 1; + } + return res; + } + case 'B': { + for (int i = 0; i < len; i++) { + res[i] = new JavaByte(byteAt(offset)); + offset += 1; + } + return res; + } + case 'C': { + for (int i = 0; i < len; i++) { + res[i] = new JavaChar(charAt(offset)); + offset += 2; + } + return res; + } + case 'S': { + for (int i = 0; i < len; i++) { + res[i] = new JavaShort(shortAt(offset)); + offset += 2; + } + return res; + } + case 'I': { + for (int i = 0; i < len; i++) { + res[i] = new JavaInt(intAt(offset)); + offset += 4; + } + return res; + } + case 'J': { + for (int i = 0; i < len; i++) { + res[i] = new JavaLong(longAt(offset)); + offset += 8; + } + return res; + } + case 'F': { + for (int i = 0; i < len; i++) { + res[i] = new JavaFloat(floatAt(offset)); + offset += 4; + } + return res; + } + case 'D': { + for (int i = 0; i < len; i++) { + res[i] = new JavaDouble(doubleAt(offset)); + offset += 8; + } + return res; + } + default: { + throw new RuntimeException("unknown primitive type?"); + } + } + } + } + + // 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 (int)(getValueLength() / divider); + } + + public JavaThing[] getElements() { + return getValue(); + } + + 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 String valueString() { + return valueString(true); + } + + public String valueString(boolean bigLimit) { + // Char arrays deserve special treatment + StringBuilder result; + JavaThing[] things = getValue(); + byte elementSignature = getElementType(); + if (elementSignature == 'C') { + result = new StringBuilder(); + for (int i = 0; i < things.length; i++) { + result.append(things[i]); + } + } else { + int limit = 8; + if (bigLimit) { + limit = 1000; + } + result = new StringBuilder("{"); + for (int i = 0; i < things.length; i++) { + if (i > 0) { + result.append(", "); + } + if (i >= limit) { + result.append("... "); + break; + } + switch (elementSignature) { + case 'Z': { + boolean val = ((JavaBoolean)things[i]).value; + if (val) { + result.append("true"); + } else { + result.append("false"); + } + break; + } + case 'B': { + byte val = ((JavaByte)things[i]).value; + result.append("0x").append(Integer.toString(val, 16)); + break; + } + case 'S': { + short val = ((JavaShort)things[i]).value; + result.append(val); + break; + } + case 'I': { + int val = ((JavaInt)things[i]).value; + result.append(val); + break; + } + case 'J': { // long + long val = ((JavaLong)things[i]).value; + result.append(val); + break; + } + case 'F': { + float val = ((JavaFloat)things[i]).value; + result.append(val); + break; + } + case 'D': { // double + double val = ((JavaDouble)things[i]).value; + result.append(val); + break; + } + default: { + throw new RuntimeException("unknown primitive type?"); + } + } + } + result.append('}'); + } + return result.toString(); + } +}