17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
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.util.Objects;
35
36 /**
37 * An array of values, that is, an array of ints, boolean, floats or the like.
38 *
39 * @author Bill Foote
40 */
41 public class JavaValueArray extends JavaLazyReadObject
42 /*imports*/ implements ArrayTypeCodes {
43
44 private static String arrayTypeName(byte sig) {
45 switch (sig) {
46 case 'B':
47 return "byte[]";
48 case 'Z':
49 return "boolean[]";
50 case 'C':
51 return "char[]";
52 case 'S':
53 return "short[]";
54 case 'I':
55 return "int[]";
56 case 'F':
57 return "float[]";
58 case 'J':
59 return "long[]";
60 case 'D':
61 return "double[]";
62 default:
63 throw new RuntimeException("invalid array element sig: " + sig);
64 }
65 }
66
67 private static int elementSize(byte type) {
68 switch (type) {
69 case 'B':
70 case 'Z':
71 return 1;
72 case 'C':
73 case 'S':
74 return 2;
75 case 'I':
76 case 'F':
77 return 4;
78 case 'J':
79 case 'D':
80 return 8;
81 default:
82 throw new RuntimeException("invalid array element type: " + type);
83 }
84 }
85
86 /*
87 * Java primitive array record (HPROF_GC_PRIM_ARRAY_DUMP) looks
88 * as below:
89 *
90 * object ID
91 * stack trace serial number (int)
92 * number of elements (int)
93 * element type (byte)
94 * array data
95 */
96 @Override
97 protected final long readValueLength() throws IOException {
98 long offset = getOffset() + idSize() + 4;
99 // length of the array in elements
100 long len = buf().getInt(offset);
101 // byte length of array
102 return len * elementSize(getElementType());
103 }
104
105 private long dataStartOffset() {
106 return getOffset() + idSize() + 4 + 4 + 1;
107 }
108
109
110 @Override
111 protected final JavaThing[] readValue() throws IOException {
112 int len = getLength();
113 long offset = dataStartOffset();
114
115 JavaThing[] res = new JavaThing[len];
116 synchronized (buf()) {
117 switch (getElementType()) {
118 case 'Z': {
119 for (int i = 0; i < len; i++) {
120 res[i] = new JavaBoolean(booleanAt(offset));
121 offset += 1;
122 }
154 for (int i = 0; i < len; i++) {
155 res[i] = new JavaLong(longAt(offset));
156 offset += 8;
157 }
158 return res;
159 }
160 case 'F': {
161 for (int i = 0; i < len; i++) {
162 res[i] = new JavaFloat(floatAt(offset));
163 offset += 4;
164 }
165 return res;
166 }
167 case 'D': {
168 for (int i = 0; i < len; i++) {
169 res[i] = new JavaDouble(doubleAt(offset));
170 offset += 8;
171 }
172 return res;
173 }
174 default: {
175 throw new RuntimeException("unknown primitive type?");
176 }
177 }
178 }
179 }
180
181 // JavaClass set only after resolve.
182 private JavaClass clazz;
183
184 // This field contains elementSignature byte and
185 // divider to be used to calculate length. Note that
186 // length of content byte[] is not same as array length.
187 // Actual array length is (byte[].length / divider)
188 private int data;
189
190 // First 8 bits of data is used for element signature
191 private static final int SIGNATURE_MASK = 0x0FF;
192
193 // Next 8 bits of data is used for length divider
194 private static final int LENGTH_DIVIDER_MASK = 0x0FF00;
195
196 // Number of bits to shift to get length divider
197 private static final int LENGTH_DIVIDER_SHIFT = 8;
198
199 public JavaValueArray(byte elementSignature, long offset) {
200 super(offset);
201 this.data = (elementSignature & SIGNATURE_MASK);
202 }
203
204 public JavaClass getClazz() {
205 return clazz;
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 byte elementSig = getElementType();
217 clazz = snapshot.findClass(arrayTypeName(elementSig));
218 if (clazz == null) {
219 clazz = snapshot.getArrayClass("" + ((char) elementSig));
220 }
221 getClazz().addInstance(this);
222 super.resolve(snapshot);
223 }
224
225 public int getLength() {
226 int divider = (data & LENGTH_DIVIDER_MASK) >>> LENGTH_DIVIDER_SHIFT;
227 if (divider == 0) {
228 byte elementSignature = getElementType();
229 switch (elementSignature) {
230 case 'B':
231 case 'Z':
232 divider = 1;
233 break;
234 case 'C':
235 case 'S':
236 divider = 2;
237 break;
238 case 'I':
239 case 'F':
240 divider = 4;
241 break;
242 case 'J':
243 case 'D':
244 divider = 8;
245 break;
246 default:
247 throw new RuntimeException("unknown primitive type: " +
248 elementSignature);
249 }
250 data |= (divider << LENGTH_DIVIDER_SHIFT);
251 }
252 return (int)(getValueLength() / divider);
253 }
254
255 public JavaThing[] getElements() {
256 return getValue();
257 }
258
259 public byte getElementType() {
260 return (byte) (data & SIGNATURE_MASK);
261 }
262
263 private void checkIndex(int index) {
264 Objects.checkIndex(index, getLength());
265 }
266
267 private void requireType(char type) {
268 if (getElementType() != type) {
269 throw new RuntimeException("not of type : " + type);
270 }
271 }
272
273 public String valueString() {
274 return valueString(true);
275 }
276
277 public String valueString(boolean bigLimit) {
278 // Char arrays deserve special treatment
279 StringBuilder result;
280 JavaThing[] things = getValue();
281 byte elementSignature = getElementType();
282 if (elementSignature == 'C') {
283 result = new StringBuilder();
284 for (int i = 0; i < things.length; i++) {
285 result.append(things[i]);
286 }
287 } else {
288 int limit = 8;
289 if (bigLimit) {
290 limit = 1000;
291 }
292 result = new StringBuilder("{");
293 for (int i = 0; i < things.length; i++) {
294 if (i > 0) {
295 result.append(", ");
296 }
297 if (i >= limit) {
298 result.append("... ");
299 break;
300 }
301 switch (elementSignature) {
302 case 'Z': {
321 case 'I': {
322 int val = ((JavaInt)things[i]).value;
323 result.append(val);
324 break;
325 }
326 case 'J': { // long
327 long val = ((JavaLong)things[i]).value;
328 result.append(val);
329 break;
330 }
331 case 'F': {
332 float val = ((JavaFloat)things[i]).value;
333 result.append(val);
334 break;
335 }
336 case 'D': { // double
337 double val = ((JavaDouble)things[i]).value;
338 result.append(val);
339 break;
340 }
341 default: {
342 throw new RuntimeException("unknown primitive type?");
343 }
344 }
345 }
346 result.append('}');
347 }
348 return result.toString();
349 }
350
351 // Tries to represent the value as string (used by JavaObject.toString).
352 public String valueAsString() {
353 if (getElementType() == 'B') {
354 JavaThing[] things = getValue();
355 byte[] bytes = new byte[things.length];
356 for (int i = 0; i < things.length; i++) {
357 bytes[i] = ((JavaByte)things[i]).value;
358 }
359 return new String(bytes);
360 }
|
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
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.util.Objects;
35
36 /**
37 * An array of values, that is, an array of ints, boolean, floats, etc.
38 * or flat array of primitive objects.
39 *
40 * @author Bill Foote
41 */
42 public class JavaValueArray extends JavaLazyReadObject
43 /*imports*/ implements ArrayTypeCodes {
44
45 private static int elementSize(byte type) {
46 switch (type) {
47 case 'B':
48 case 'Z':
49 return 1;
50 case 'C':
51 case 'S':
52 return 2;
53 case 'I':
54 case 'F':
55 return 4;
56 case 'J':
57 case 'D':
58 return 8;
59 default:
60 throw new RuntimeException("invalid array element type: " + type);
61 }
62 }
63
64 /*
65 * Java primitive array record (HPROF_GC_PRIM_ARRAY_DUMP) looks
66 * as below:
67 *
68 * object ID
69 * stack trace serial number (int)
70 * number of elements (int)
71 * element type (byte)
72 * array data
73 */
74 @Override
75 protected final long readValueLength() throws IOException {
76 long offset = getOffset() + idSize() + 4;
77 // length of the array in elements
78 long len = buf().getInt(offset);
79 // byte length of array
80 return len * elementSize(getRealElementType());
81 }
82
83 private long dataStartOffset() {
84 return getOffset() + idSize() + 4 + 4 + 1;
85 }
86
87
88 @Override
89 protected final JavaThing[] readValue() throws IOException {
90 int len = getLength();
91 long offset = dataStartOffset();
92
93 JavaThing[] res = new JavaThing[len];
94 synchronized (buf()) {
95 switch (getElementType()) {
96 case 'Z': {
97 for (int i = 0; i < len; i++) {
98 res[i] = new JavaBoolean(booleanAt(offset));
99 offset += 1;
100 }
132 for (int i = 0; i < len; i++) {
133 res[i] = new JavaLong(longAt(offset));
134 offset += 8;
135 }
136 return res;
137 }
138 case 'F': {
139 for (int i = 0; i < len; i++) {
140 res[i] = new JavaFloat(floatAt(offset));
141 offset += 4;
142 }
143 return res;
144 }
145 case 'D': {
146 for (int i = 0; i < len; i++) {
147 res[i] = new JavaDouble(doubleAt(offset));
148 offset += 8;
149 }
150 return res;
151 }
152 case 'Q': {
153 for (int i = 0; i < len; i++) {
154 res[i] = new InlinedJavaObject(flatArrayElementClass, offset);
155 offset += flatArrayElementClass.getInlinedInstanceSize();
156 }
157 return res;
158 }
159 default: {
160 throw new RuntimeException("unknown primitive type?");
161 }
162 }
163 }
164 }
165
166 // JavaClass set only after resolve.
167 private JavaClass clazz;
168
169 private long objID;
170
171 // This field contains elementSignature byte and
172 // divider to be used to calculate length. Note that
173 // length of content byte[] is not same as array length.
174 // Actual array length is (byte[].length / divider)
175 private int data;
176
177 // First 8 bits of data is used for element signature
178 private static final int SIGNATURE_MASK = 0x0FF;
179
180 // Next 8 bits of data is used for length divider
181 private static final int LENGTH_DIVIDER_MASK = 0x0FF00;
182
183 // Number of bits to shift to get length divider
184 private static final int LENGTH_DIVIDER_SHIFT = 8;
185
186 // Flat array support.
187 private JavaClass flatArrayElementClass;
188
189 public JavaValueArray(long id, byte elementSignature, long offset) {
190 super(offset);
191 this.objID = id;
192 this.data = (elementSignature & SIGNATURE_MASK);
193 }
194
195 public JavaClass getClazz() {
196 return clazz;
197 }
198
199 public boolean isFlatArray() {
200 return flatArrayElementClass != null;
201 }
202
203 public JavaClass getFlatElementClazz() {
204 return flatArrayElementClass;
205 }
206
207 public void visitReferencedObjects(JavaHeapObjectVisitor v) {
208 super.visitReferencedObjects(v);
209 }
210
211 public void resolve(Snapshot snapshot) {
212 if (clazz instanceof JavaClass) {
213 return;
214 }
215
216 byte elementType = getElementType();
217 String elementSig = "" + (char)elementType;
218 // Check if this is a flat array of primitive objects.
219 Number elementClassID = snapshot.findFlatArrayElementType(objID);
220 if (elementClassID != null) {
221 // This is flat array.
222 JavaHeapObject elementClazz = snapshot.findThing(getIdValue(elementClassID));
223 if (elementClazz instanceof JavaClass elementJavaClazz) {
224 flatArrayElementClass = elementJavaClazz;
225 // need to resolve the element class
226 flatArrayElementClass.resolve(snapshot);
227 elementSig = "Q" + flatArrayElementClass.getName() + ";";
228 } else {
229 // The class not found.
230 System.out.println("WARNING: flat array element class not found");
231 }
232 }
233 clazz = snapshot.getArrayClass(elementSig);
234 getClazz().addInstance(this);
235 super.resolve(snapshot);
236 }
237
238 public int getLength() {
239 int divider = (data & LENGTH_DIVIDER_MASK) >>> LENGTH_DIVIDER_SHIFT;
240 if (divider == 0) {
241 byte elementSignature = getElementType();
242 switch (elementSignature) {
243 case 'B':
244 case 'Z':
245 divider = 1;
246 break;
247 case 'C':
248 case 'S':
249 divider = 2;
250 break;
251 case 'I':
252 case 'F':
253 divider = 4;
254 break;
255 case 'J':
256 case 'D':
257 divider = 8;
258 break;
259 case 'Q':
260 divider = flatArrayElementClass.getInlinedInstanceSize();
261 break;
262 default:
263 throw new RuntimeException("unknown primitive type: " +
264 elementSignature);
265 }
266 data |= (divider << LENGTH_DIVIDER_SHIFT);
267 }
268 return (int)(getValueLength() / divider);
269 }
270
271 public JavaThing[] getElements() {
272 return getValue();
273 }
274
275 public byte getElementType() {
276 return isFlatArray() ? (byte)'Q' : getRealElementType();
277 }
278
279 private byte getRealElementType() {
280 return (byte) (data & SIGNATURE_MASK);
281 }
282
283 private void checkIndex(int index) {
284 Objects.checkIndex(index, getLength());
285 }
286
287 private void requireType(char type) {
288 if (getElementType() != type) {
289 throw new RuntimeException("not of type : " + type);
290 }
291 }
292
293 public String valueString() {
294 return valueString(true);
295 }
296
297 public String valueString(boolean bigLimit) {
298 // Char arrays deserve special treatment
299 StringBuilder result;
300 JavaThing[] things = getValue();
301 byte elementSignature = getElementType();
302 if (elementSignature == 'C' && !isFlatArray()) {
303 result = new StringBuilder();
304 for (int i = 0; i < things.length; i++) {
305 result.append(things[i]);
306 }
307 } else {
308 int limit = 8;
309 if (bigLimit) {
310 limit = 1000;
311 }
312 result = new StringBuilder("{");
313 for (int i = 0; i < things.length; i++) {
314 if (i > 0) {
315 result.append(", ");
316 }
317 if (i >= limit) {
318 result.append("... ");
319 break;
320 }
321 switch (elementSignature) {
322 case 'Z': {
341 case 'I': {
342 int val = ((JavaInt)things[i]).value;
343 result.append(val);
344 break;
345 }
346 case 'J': { // long
347 long val = ((JavaLong)things[i]).value;
348 result.append(val);
349 break;
350 }
351 case 'F': {
352 float val = ((JavaFloat)things[i]).value;
353 result.append(val);
354 break;
355 }
356 case 'D': { // double
357 double val = ((JavaDouble)things[i]).value;
358 result.append(val);
359 break;
360 }
361 case 'Q': {
362 InlinedJavaObject obj = (InlinedJavaObject)things[i];
363 result.append(obj);
364 }
365 default: {
366 throw new RuntimeException("unknown primitive type?");
367 }
368 }
369 }
370 result.append('}');
371 }
372 return result.toString();
373 }
374
375 // Tries to represent the value as string (used by JavaObject.toString).
376 public String valueAsString() {
377 if (getElementType() == 'B') {
378 JavaThing[] things = getValue();
379 byte[] bytes = new byte[things.length];
380 for (int i = 0; i < things.length; i++) {
381 bytes[i] = ((JavaByte)things[i]).value;
382 }
383 return new String(bytes);
384 }
|