jdk/src/jdk.dev/share/classes/com/sun/tools/hat/internal/model/JavaValueArray.java
changeset 30779 92bb39a2a876
parent 30778 43087a23d825
parent 30736 ff3fc75f3214
child 30780 b83f001a855d
child 30886 d2a0ec86d6ef
equal deleted inserted replaced
30778:43087a23d825 30779:92bb39a2a876
     1 /*
       
     2  * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Oracle designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Oracle in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    22  * or visit www.oracle.com if you need additional information or have any
       
    23  * questions.
       
    24  */
       
    25 
       
    26 
       
    27 /*
       
    28  * The Original Code is HAT. The Initial Developer of the
       
    29  * Original Code is Bill Foote, with contributions from others
       
    30  * at JavaSoft/Sun.
       
    31  */
       
    32 
       
    33 package com.sun.tools.hat.internal.model;
       
    34 
       
    35 import com.sun.tools.hat.internal.parser.ReadBuffer;
       
    36 import java.io.IOException;
       
    37 
       
    38 /**
       
    39  * An array of values, that is, an array of ints, boolean, floats or the like.
       
    40  *
       
    41  * @author      Bill Foote
       
    42  */
       
    43 public class JavaValueArray extends JavaLazyReadObject
       
    44                 /*imports*/ implements ArrayTypeCodes {
       
    45 
       
    46     private static String arrayTypeName(byte sig) {
       
    47         switch (sig) {
       
    48             case 'B':
       
    49                 return "byte[]";
       
    50             case 'Z':
       
    51                 return "boolean[]";
       
    52             case 'C':
       
    53                 return "char[]";
       
    54             case 'S':
       
    55                 return "short[]";
       
    56             case 'I':
       
    57                 return "int[]";
       
    58             case 'F':
       
    59                 return "float[]";
       
    60             case 'J':
       
    61                 return "long[]";
       
    62             case 'D':
       
    63                 return "double[]";
       
    64             default:
       
    65                 throw new RuntimeException("invalid array element sig: " + sig);
       
    66         }
       
    67     }
       
    68 
       
    69     private static int elementSize(byte type) {
       
    70         switch (type) {
       
    71             case T_BYTE:
       
    72             case T_BOOLEAN:
       
    73                 return 1;
       
    74             case T_CHAR:
       
    75             case T_SHORT:
       
    76                 return 2;
       
    77             case T_INT:
       
    78             case T_FLOAT:
       
    79                 return 4;
       
    80             case T_LONG:
       
    81             case T_DOUBLE:
       
    82                 return 8;
       
    83             default:
       
    84                 throw new RuntimeException("invalid array element type: " + type);
       
    85         }
       
    86     }
       
    87 
       
    88     /*
       
    89      * Java primitive array record (HPROF_GC_PRIM_ARRAY_DUMP) looks
       
    90      * as below:
       
    91      *
       
    92      *    object ID
       
    93      *    stack trace serial number (int)
       
    94      *    length of the instance data (int)
       
    95      *    element type (byte)
       
    96      *    array data
       
    97      */
       
    98     protected final int readValueLength() throws IOException {
       
    99         JavaClass cl = getClazz();
       
   100         ReadBuffer buf = cl.getReadBuffer();
       
   101         int idSize = cl.getIdentifierSize();
       
   102         long offset = getOffset() + idSize + 4;
       
   103         // length of the array
       
   104         int len = buf.getInt(offset);
       
   105         // typecode of array element type
       
   106         byte type = buf.getByte(offset + 4);
       
   107         return len * elementSize(type);
       
   108     }
       
   109 
       
   110     protected final byte[] readValue() throws IOException {
       
   111         JavaClass cl = getClazz();
       
   112         ReadBuffer buf = cl.getReadBuffer();
       
   113         int idSize = cl.getIdentifierSize();
       
   114         long offset = getOffset() + idSize + 4;
       
   115         // length of the array
       
   116         int length = buf.getInt(offset);
       
   117         // typecode of array element type
       
   118         byte type = buf.getByte(offset + 4);
       
   119         if (length == 0) {
       
   120             return Snapshot.EMPTY_BYTE_ARRAY;
       
   121         } else {
       
   122             length *= elementSize(type);
       
   123             byte[] res = new byte[length];
       
   124             buf.get(offset + 5, res);
       
   125             return res;
       
   126         }
       
   127     }
       
   128 
       
   129     // JavaClass set only after resolve.
       
   130     private JavaClass clazz;
       
   131 
       
   132     // This field contains elementSignature byte and
       
   133     // divider to be used to calculate length. Note that
       
   134     // length of content byte[] is not same as array length.
       
   135     // Actual array length is (byte[].length / divider)
       
   136     private int data;
       
   137 
       
   138     // First 8 bits of data is used for element signature
       
   139     private static final int SIGNATURE_MASK = 0x0FF;
       
   140 
       
   141     // Next 8 bits of data is used for length divider
       
   142     private static final int LENGTH_DIVIDER_MASK = 0x0FF00;
       
   143 
       
   144     // Number of bits to shift to get length divider
       
   145     private static final int LENGTH_DIVIDER_SHIFT = 8;
       
   146 
       
   147     public JavaValueArray(byte elementSignature, long offset) {
       
   148         super(offset);
       
   149         this.data = (elementSignature & SIGNATURE_MASK);
       
   150     }
       
   151 
       
   152     public JavaClass getClazz() {
       
   153         return clazz;
       
   154     }
       
   155 
       
   156     public void visitReferencedObjects(JavaHeapObjectVisitor v) {
       
   157         super.visitReferencedObjects(v);
       
   158     }
       
   159 
       
   160     public void resolve(Snapshot snapshot) {
       
   161         if (clazz instanceof JavaClass) {
       
   162             return;
       
   163         }
       
   164         byte elementSig = getElementType();
       
   165         clazz = snapshot.findClass(arrayTypeName(elementSig));
       
   166         if (clazz == null) {
       
   167             clazz = snapshot.getArrayClass("" + ((char) elementSig));
       
   168         }
       
   169         getClazz().addInstance(this);
       
   170         super.resolve(snapshot);
       
   171     }
       
   172 
       
   173     public int getLength() {
       
   174         int divider = (data & LENGTH_DIVIDER_MASK) >>> LENGTH_DIVIDER_SHIFT;
       
   175         if (divider == 0) {
       
   176             byte elementSignature = getElementType();
       
   177             switch (elementSignature) {
       
   178             case 'B':
       
   179             case 'Z':
       
   180                 divider = 1;
       
   181                 break;
       
   182             case 'C':
       
   183             case 'S':
       
   184                 divider = 2;
       
   185                 break;
       
   186             case 'I':
       
   187             case 'F':
       
   188                 divider = 4;
       
   189                 break;
       
   190             case 'J':
       
   191             case 'D':
       
   192                 divider = 8;
       
   193                 break;
       
   194             default:
       
   195                 throw new RuntimeException("unknown primitive type: " +
       
   196                                 elementSignature);
       
   197             }
       
   198             data |= (divider << LENGTH_DIVIDER_SHIFT);
       
   199         }
       
   200         return (getValueLength() / divider);
       
   201     }
       
   202 
       
   203     public Object getElements() {
       
   204         final int len = getLength();
       
   205         final byte et = getElementType();
       
   206         byte[] data = getValue();
       
   207         int index = 0;
       
   208         switch (et) {
       
   209             case 'Z': {
       
   210                 boolean[] res = new boolean[len];
       
   211                 for (int i = 0; i < len; i++) {
       
   212                     res[i] = booleanAt(index, data);
       
   213                     index++;
       
   214                 }
       
   215                 return res;
       
   216             }
       
   217             case 'B': {
       
   218                 byte[] res = new byte[len];
       
   219                 for (int i = 0; i < len; i++) {
       
   220                     res[i] = byteAt(index, data);
       
   221                     index++;
       
   222                 }
       
   223                 return res;
       
   224             }
       
   225             case 'C': {
       
   226                 char[] res = new char[len];
       
   227                 for (int i = 0; i < len; i++) {
       
   228                     res[i] = charAt(index, data);
       
   229                     index += 2;
       
   230                 }
       
   231                 return res;
       
   232             }
       
   233             case 'S': {
       
   234                 short[] res = new short[len];
       
   235                 for (int i = 0; i < len; i++) {
       
   236                     res[i] = shortAt(index, data);
       
   237                     index += 2;
       
   238                 }
       
   239                 return res;
       
   240             }
       
   241             case 'I': {
       
   242                 int[] res = new int[len];
       
   243                 for (int i = 0; i < len; i++) {
       
   244                     res[i] = intAt(index, data);
       
   245                     index += 4;
       
   246                 }
       
   247                 return res;
       
   248             }
       
   249             case 'J': {
       
   250                 long[] res = new long[len];
       
   251                 for (int i = 0; i < len; i++) {
       
   252                     res[i] = longAt(index, data);
       
   253                     index += 8;
       
   254                 }
       
   255                 return res;
       
   256             }
       
   257             case 'F': {
       
   258                 float[] res = new float[len];
       
   259                 for (int i = 0; i < len; i++) {
       
   260                     res[i] = floatAt(index, data);
       
   261                     index += 4;
       
   262                 }
       
   263                 return res;
       
   264             }
       
   265             case 'D': {
       
   266                 double[] res = new double[len];
       
   267                 for (int i = 0; i < len; i++) {
       
   268                     res[i] = doubleAt(index, data);
       
   269                     index += 8;
       
   270                 }
       
   271                 return res;
       
   272             }
       
   273             default: {
       
   274                 throw new RuntimeException("unknown primitive type?");
       
   275             }
       
   276         }
       
   277     }
       
   278 
       
   279     public byte getElementType() {
       
   280         return (byte) (data & SIGNATURE_MASK);
       
   281     }
       
   282 
       
   283     private void checkIndex(int index) {
       
   284         if (index < 0 || index >= getLength()) {
       
   285             throw new ArrayIndexOutOfBoundsException(index);
       
   286         }
       
   287     }
       
   288 
       
   289     private void requireType(char type) {
       
   290         if (getElementType() != type) {
       
   291             throw new RuntimeException("not of type : " + type);
       
   292         }
       
   293     }
       
   294 
       
   295     public boolean getBooleanAt(int index) {
       
   296         checkIndex(index);
       
   297         requireType('Z');
       
   298         return booleanAt(index, getValue());
       
   299     }
       
   300 
       
   301     public byte getByteAt(int index) {
       
   302         checkIndex(index);
       
   303         requireType('B');
       
   304         return byteAt(index, getValue());
       
   305     }
       
   306 
       
   307     public char getCharAt(int index) {
       
   308         checkIndex(index);
       
   309         requireType('C');
       
   310         return charAt(index << 1, getValue());
       
   311     }
       
   312 
       
   313     public short getShortAt(int index) {
       
   314         checkIndex(index);
       
   315         requireType('S');
       
   316         return shortAt(index << 1, getValue());
       
   317     }
       
   318 
       
   319     public int getIntAt(int index) {
       
   320         checkIndex(index);
       
   321         requireType('I');
       
   322         return intAt(index << 2, getValue());
       
   323     }
       
   324 
       
   325     public long getLongAt(int index) {
       
   326         checkIndex(index);
       
   327         requireType('J');
       
   328         return longAt(index << 3, getValue());
       
   329     }
       
   330 
       
   331     public float getFloatAt(int index) {
       
   332         checkIndex(index);
       
   333         requireType('F');
       
   334         return floatAt(index << 2, getValue());
       
   335     }
       
   336 
       
   337     public double getDoubleAt(int index) {
       
   338         checkIndex(index);
       
   339         requireType('D');
       
   340         return doubleAt(index << 3, getValue());
       
   341     }
       
   342 
       
   343     public String valueString() {
       
   344         return valueString(true);
       
   345     }
       
   346 
       
   347     public String valueString(boolean bigLimit) {
       
   348         // Char arrays deserve special treatment
       
   349         StringBuilder result;
       
   350         byte[] value = getValue();
       
   351         int max = value.length;
       
   352         byte elementSignature = getElementType();
       
   353         if (elementSignature == 'C')  {
       
   354             result = new StringBuilder();
       
   355             for (int i = 0; i < value.length; ) {
       
   356                 char val = charAt(i, value);
       
   357                 result.append(val);
       
   358                 i += 2;
       
   359             }
       
   360         } else {
       
   361             int limit = 8;
       
   362             if (bigLimit) {
       
   363                 limit = 1000;
       
   364             }
       
   365             result = new StringBuilder("{");
       
   366             int num = 0;
       
   367             for (int i = 0; i < value.length; ) {
       
   368                 if (num > 0) {
       
   369                     result.append(", ");
       
   370                 }
       
   371                 if (num >= limit) {
       
   372                     result.append("... ");
       
   373                     break;
       
   374                 }
       
   375                 num++;
       
   376                 switch (elementSignature) {
       
   377                     case 'Z': {
       
   378                         boolean val = booleanAt(i, value);
       
   379                         if (val) {
       
   380                             result.append("true");
       
   381                         } else {
       
   382                             result.append("false");
       
   383                         }
       
   384                         i++;
       
   385                         break;
       
   386                     }
       
   387                     case 'B': {
       
   388                         int val = 0xFF & byteAt(i, value);
       
   389                         result.append("0x").append(Integer.toString(val, 16));
       
   390                         i++;
       
   391                         break;
       
   392                     }
       
   393                     case 'S': {
       
   394                         short val = shortAt(i, value);
       
   395                         i += 2;
       
   396                         result.append(val);
       
   397                         break;
       
   398                     }
       
   399                     case 'I': {
       
   400                         int val = intAt(i, value);
       
   401                         i += 4;
       
   402                         result.append(val);
       
   403                         break;
       
   404                     }
       
   405                     case 'J': {         // long
       
   406                         long val = longAt(i, value);
       
   407                         result.append(val);
       
   408                         i += 8;
       
   409                         break;
       
   410                     }
       
   411                     case 'F': {
       
   412                         float val = floatAt(i, value);
       
   413                         result.append(val);
       
   414                         i += 4;
       
   415                         break;
       
   416                     }
       
   417                     case 'D': {         // double
       
   418                         double val = doubleAt(i, value);
       
   419                         result.append(val);
       
   420                         i += 8;
       
   421                         break;
       
   422                     }
       
   423                     default: {
       
   424                         throw new RuntimeException("unknown primitive type?");
       
   425                     }
       
   426                 }
       
   427             }
       
   428             result.append('}');
       
   429         }
       
   430         return result.toString();
       
   431     }
       
   432 
       
   433 }