18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24
25 /*
26 * The Original Code is HAT. The Initial Developer of the
27 * Original Code is Bill Foote, with contributions from others
28 * at JavaSoft/Sun.
29 */
30
31 package jdk.test.lib.hprof.model;
32
33 import java.io.IOException;
34 import java.nio.ByteOrder;
35 import java.util.Objects;
36
37 /**
38 * An array of values, that is, an array of ints, boolean, floats or the like.
39 *
40 * @author Bill Foote
41 */
42 public class JavaValueArray extends JavaLazyReadObject
43 /*imports*/ implements ArrayTypeCodes {
44
45 private static String arrayTypeName(byte sig) {
46 switch (sig) {
47 case 'B':
48 return "byte[]";
49 case 'Z':
50 return "boolean[]";
51 case 'C':
52 return "char[]";
53 case 'S':
54 return "short[]";
55 case 'I':
56 return "int[]";
57 case 'F':
58 return "float[]";
59 case 'J':
60 return "long[]";
61 case 'D':
62 return "double[]";
63 default:
64 throw new RuntimeException("invalid array element sig: " + sig);
65 }
66 }
67
68 private static int elementSize(byte type) {
69 switch (type) {
70 case 'B':
71 case 'Z':
72 return 1;
73 case 'C':
74 case 'S':
75 return 2;
76 case 'I':
77 case 'F':
78 return 4;
79 case 'J':
80 case 'D':
81 return 8;
82 default:
83 throw new RuntimeException("invalid array element type: " + type);
84 }
85 }
86
87 /*
88 * Java primitive array record (HPROF_GC_PRIM_ARRAY_DUMP) looks
89 * as below:
90 *
91 * object ID
92 * stack trace serial number (int)
93 * number of elements (int)
94 * element type (byte)
95 * array data
96 */
97 @Override
98 protected final long readValueLength() throws IOException {
99 long offset = getOffset() + idSize() + 4;
100 // length of the array in elements
101 long len = buf().getInt(offset);
102 // byte length of array
103 return len * elementSize(getElementType());
104 }
105
106 private long dataStartOffset() {
107 return getOffset() + idSize() + 4 + 4 + 1;
108 }
109
110
111 @Override
112 protected final JavaThing[] readValue() throws IOException {
113 int len = getLength();
114 long offset = dataStartOffset();
115
116 JavaThing[] res = new JavaThing[len];
117 synchronized (buf()) {
118 switch (getElementType()) {
119 case 'Z': {
120 for (int i = 0; i < len; i++) {
121 res[i] = new JavaBoolean(booleanAt(offset));
122 offset += 1;
123 }
155 for (int i = 0; i < len; i++) {
156 res[i] = new JavaLong(longAt(offset));
157 offset += 8;
158 }
159 return res;
160 }
161 case 'F': {
162 for (int i = 0; i < len; i++) {
163 res[i] = new JavaFloat(floatAt(offset));
164 offset += 4;
165 }
166 return res;
167 }
168 case 'D': {
169 for (int i = 0; i < len; i++) {
170 res[i] = new JavaDouble(doubleAt(offset));
171 offset += 8;
172 }
173 return res;
174 }
175 default: {
176 throw new RuntimeException("unknown primitive type?");
177 }
178 }
179 }
180 }
181
182 // JavaClass set only after resolve.
183 private JavaClass clazz;
184
185 // This field contains elementSignature byte and
186 // divider to be used to calculate length. Note that
187 // length of content byte[] is not same as array length.
188 // Actual array length is (byte[].length / divider)
189 private int data;
190
191 // First 8 bits of data is used for element signature
192 private static final int SIGNATURE_MASK = 0x0FF;
193
194 // Next 8 bits of data is used for length divider
195 private static final int LENGTH_DIVIDER_MASK = 0x0FF00;
196
197 // Number of bits to shift to get length divider
198 private static final int LENGTH_DIVIDER_SHIFT = 8;
199
200 public JavaValueArray(byte elementSignature, long offset) {
201 super(offset);
202 this.data = (elementSignature & SIGNATURE_MASK);
203 }
204
205 public JavaClass getClazz() {
206 return clazz;
207 }
208
209 public void visitReferencedObjects(JavaHeapObjectVisitor v) {
210 super.visitReferencedObjects(v);
211 }
212
213 public void resolve(Snapshot snapshot) {
214 if (clazz instanceof JavaClass) {
215 return;
216 }
217 byte elementSig = getElementType();
218 clazz = snapshot.findClass(arrayTypeName(elementSig));
219 if (clazz == null) {
220 clazz = snapshot.getArrayClass("" + ((char) elementSig));
221 }
222 getClazz().addInstance(this);
223 super.resolve(snapshot);
224 }
225
226 public int getLength() {
227 int divider = (data & LENGTH_DIVIDER_MASK) >>> LENGTH_DIVIDER_SHIFT;
228 if (divider == 0) {
229 byte elementSignature = getElementType();
230 switch (elementSignature) {
231 case 'B':
232 case 'Z':
233 divider = 1;
234 break;
235 case 'C':
236 case 'S':
237 divider = 2;
238 break;
239 case 'I':
240 case 'F':
241 divider = 4;
242 break;
243 case 'J':
244 case 'D':
245 divider = 8;
246 break;
247 default:
248 throw new RuntimeException("unknown primitive type: " +
249 elementSignature);
250 }
251 data |= (divider << LENGTH_DIVIDER_SHIFT);
252 }
253 return (int)(getValueLength() / divider);
254 }
255
256 public JavaThing[] getElements() {
257 return getValue();
258 }
259
260 public byte getElementType() {
261 return (byte) (data & SIGNATURE_MASK);
262 }
263
264 private void checkIndex(int index) {
265 Objects.checkIndex(index, getLength());
266 }
267
268 private void requireType(char type) {
269 if (getElementType() != type) {
270 throw new RuntimeException("not of type : " + type);
271 }
272 }
273
274 public String valueString() {
275 return valueString(true);
276 }
277
278 public String valueString(boolean bigLimit) {
279 // Char arrays deserve special treatment
280 StringBuilder result;
281 JavaThing[] things = getValue();
282 byte elementSignature = getElementType();
283 if (elementSignature == 'C') {
284 result = new StringBuilder();
285 for (int i = 0; i < things.length; i++) {
286 result.append(things[i]);
287 }
288 } else {
289 int limit = 8;
290 if (bigLimit) {
291 limit = 1000;
292 }
293 result = new StringBuilder("{");
294 for (int i = 0; i < things.length; i++) {
295 if (i > 0) {
296 result.append(", ");
297 }
298 if (i >= limit) {
299 result.append("... ");
300 break;
301 }
302 switch (elementSignature) {
303 case 'Z': {
|
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24
25 /*
26 * The Original Code is HAT. The Initial Developer of the
27 * Original Code is Bill Foote, with contributions from others
28 * at JavaSoft/Sun.
29 */
30
31 package jdk.test.lib.hprof.model;
32
33 import java.io.IOException;
34 import java.nio.ByteOrder;
35 import java.util.Objects;
36
37 /**
38 * An array of values, that is, an array of ints, boolean, floats, etc.
39 * or flat array of primitive objects.
40 *
41 * @author Bill Foote
42 */
43 public class JavaValueArray extends JavaLazyReadObject
44 /*imports*/ implements ArrayTypeCodes {
45
46 private static int elementSize(byte type) {
47 switch (type) {
48 case 'B':
49 case 'Z':
50 return 1;
51 case 'C':
52 case 'S':
53 return 2;
54 case 'I':
55 case 'F':
56 return 4;
57 case 'J':
58 case 'D':
59 return 8;
60 default:
61 throw new RuntimeException("invalid array element type: " + type);
62 }
63 }
64
65 /*
66 * Java primitive array record (HPROF_GC_PRIM_ARRAY_DUMP) looks
67 * as below:
68 *
69 * object ID
70 * stack trace serial number (int)
71 * number of elements (int)
72 * element type (byte)
73 * array data
74 */
75 @Override
76 protected final long readValueLength() throws IOException {
77 long offset = getOffset() + idSize() + 4;
78 // length of the array in elements
79 long len = buf().getInt(offset);
80 // byte length of array
81 return len * elementSize(getRealElementType());
82 }
83
84 private long dataStartOffset() {
85 return getOffset() + idSize() + 4 + 4 + 1;
86 }
87
88
89 @Override
90 protected final JavaThing[] readValue() throws IOException {
91 int len = getLength();
92 long offset = dataStartOffset();
93
94 JavaThing[] res = new JavaThing[len];
95 synchronized (buf()) {
96 switch (getElementType()) {
97 case 'Z': {
98 for (int i = 0; i < len; i++) {
99 res[i] = new JavaBoolean(booleanAt(offset));
100 offset += 1;
101 }
133 for (int i = 0; i < len; i++) {
134 res[i] = new JavaLong(longAt(offset));
135 offset += 8;
136 }
137 return res;
138 }
139 case 'F': {
140 for (int i = 0; i < len; i++) {
141 res[i] = new JavaFloat(floatAt(offset));
142 offset += 4;
143 }
144 return res;
145 }
146 case 'D': {
147 for (int i = 0; i < len; i++) {
148 res[i] = new JavaDouble(doubleAt(offset));
149 offset += 8;
150 }
151 return res;
152 }
153 case 'Q': {
154 for (int i = 0; i < len; i++) {
155 res[i] = new InlinedJavaObject(flatArrayElementClass, offset);
156 offset += flatArrayElementClass.getInlinedInstanceSize();
157 }
158 return res;
159 }
160 default: {
161 throw new RuntimeException("unknown primitive type?");
162 }
163 }
164 }
165 }
166
167 // JavaClass set only after resolve.
168 private JavaClass clazz;
169
170 private long objID;
171
172 // This field contains elementSignature byte and
173 // divider to be used to calculate length. Note that
174 // length of content byte[] is not same as array length.
175 // Actual array length is (byte[].length / divider)
176 private int data;
177
178 // First 8 bits of data is used for element signature
179 private static final int SIGNATURE_MASK = 0x0FF;
180
181 // Next 8 bits of data is used for length divider
182 private static final int LENGTH_DIVIDER_MASK = 0x0FF00;
183
184 // Number of bits to shift to get length divider
185 private static final int LENGTH_DIVIDER_SHIFT = 8;
186
187 // Flat array support.
188 private JavaClass flatArrayElementClass;
189
190 public JavaValueArray(long id, byte elementSignature, long offset) {
191 super(offset);
192 this.objID = id;
193 this.data = (elementSignature & SIGNATURE_MASK);
194 }
195
196 public JavaClass getClazz() {
197 return clazz;
198 }
199
200 public boolean isFlatArray() {
201 return flatArrayElementClass != null;
202 }
203
204 public JavaClass getFlatElementClazz() {
205 return flatArrayElementClass;
206 }
207
208 public void visitReferencedObjects(JavaHeapObjectVisitor v) {
209 super.visitReferencedObjects(v);
210 }
211
212 public void resolve(Snapshot snapshot) {
213 if (clazz instanceof JavaClass) {
214 return;
215 }
216
217 byte elementType = getElementType();
218 String elementSig = "" + (char)elementType;
219 // Check if this is a flat array of primitive objects.
220 Number elementClassID = snapshot.findFlatArrayElementType(objID);
221 if (elementClassID != null) {
222 // This is flat array.
223 JavaHeapObject elementClazz = snapshot.findThing(getIdValue(elementClassID));
224 if (elementClazz instanceof JavaClass elementJavaClazz) {
225 flatArrayElementClass = elementJavaClazz;
226 // need to resolve the element class
227 flatArrayElementClass.resolve(snapshot);
228 elementSig = "Q" + flatArrayElementClass.getName() + ";";
229 } else {
230 // The class not found.
231 System.out.println("WARNING: flat array element class not found");
232 }
233 }
234 clazz = snapshot.getArrayClass(elementSig);
235 getClazz().addInstance(this);
236 super.resolve(snapshot);
237 }
238
239 public int getLength() {
240 int divider = (data & LENGTH_DIVIDER_MASK) >>> LENGTH_DIVIDER_SHIFT;
241 if (divider == 0) {
242 byte elementSignature = getElementType();
243 switch (elementSignature) {
244 case 'B':
245 case 'Z':
246 divider = 1;
247 break;
248 case 'C':
249 case 'S':
250 divider = 2;
251 break;
252 case 'I':
253 case 'F':
254 divider = 4;
255 break;
256 case 'J':
257 case 'D':
258 divider = 8;
259 break;
260 case 'Q':
261 divider = flatArrayElementClass.getInlinedInstanceSize();
262 break;
263 default:
264 throw new RuntimeException("unknown primitive type: " +
265 elementSignature);
266 }
267 data |= (divider << LENGTH_DIVIDER_SHIFT);
268 }
269 return (int)(getValueLength() / divider);
270 }
271
272 public JavaThing[] getElements() {
273 return getValue();
274 }
275
276 public byte getElementType() {
277 return isFlatArray() ? (byte)'Q' : getRealElementType();
278 }
279
280 private byte getRealElementType() {
281 return (byte) (data & SIGNATURE_MASK);
282 }
283
284 private void checkIndex(int index) {
285 Objects.checkIndex(index, getLength());
286 }
287
288 private void requireType(char type) {
289 if (getElementType() != type) {
290 throw new RuntimeException("not of type : " + type);
291 }
292 }
293
294 public String valueString() {
295 return valueString(true);
296 }
297
298 public String valueString(boolean bigLimit) {
299 // Char arrays deserve special treatment
300 StringBuilder result;
301 JavaThing[] things = getValue();
302 byte elementSignature = getElementType();
303 if (elementSignature == 'C' && !isFlatArray()) {
304 result = new StringBuilder();
305 for (int i = 0; i < things.length; i++) {
306 result.append(things[i]);
307 }
308 } else {
309 int limit = 8;
310 if (bigLimit) {
311 limit = 1000;
312 }
313 result = new StringBuilder("{");
314 for (int i = 0; i < things.length; i++) {
315 if (i > 0) {
316 result.append(", ");
317 }
318 if (i >= limit) {
319 result.append("... ");
320 break;
321 }
322 switch (elementSignature) {
323 case 'Z': {
|