35
36 abstract class GraphProtocol<Graph, Node, NodeClass, Edges, Block, ResolvedJavaMethod, ResolvedJavaField, Signature, NodeSourcePosition> implements Closeable {
37 private static final Charset UTF8 = Charset.forName("UTF-8");
38
39 private static final int CONSTANT_POOL_MAX_SIZE = 8000;
40
41 private static final int BEGIN_GROUP = 0x00;
42 private static final int BEGIN_GRAPH = 0x01;
43 private static final int CLOSE_GROUP = 0x02;
44
45 private static final int POOL_NEW = 0x00;
46 private static final int POOL_STRING = 0x01;
47 private static final int POOL_ENUM = 0x02;
48 private static final int POOL_CLASS = 0x03;
49 private static final int POOL_METHOD = 0x04;
50 private static final int POOL_NULL = 0x05;
51 private static final int POOL_NODE_CLASS = 0x06;
52 private static final int POOL_FIELD = 0x07;
53 private static final int POOL_SIGNATURE = 0x08;
54 private static final int POOL_NODE_SOURCE_POSITION = 0x09;
55
56 private static final int PROPERTY_POOL = 0x00;
57 private static final int PROPERTY_INT = 0x01;
58 private static final int PROPERTY_LONG = 0x02;
59 private static final int PROPERTY_DOUBLE = 0x03;
60 private static final int PROPERTY_FLOAT = 0x04;
61 private static final int PROPERTY_TRUE = 0x05;
62 private static final int PROPERTY_FALSE = 0x06;
63 private static final int PROPERTY_ARRAY = 0x07;
64 private static final int PROPERTY_SUBGRAPH = 0x08;
65
66 private static final int KLASS = 0x00;
67 private static final int ENUM_KLASS = 0x01;
68
69 private static final byte[] MAGIC_BYTES = {'B', 'I', 'G', 'V'};
70
71 private final ConstantPool constantPool;
72 private final ByteBuffer buffer;
73 private final WritableByteChannel channel;
74 private final int versionMajor;
75 private final int versionMinor;
76
77 protected GraphProtocol(WritableByteChannel channel) throws IOException {
78 this(channel, 4, 0);
79 }
80
81 private GraphProtocol(WritableByteChannel channel, int major, int minor) throws IOException {
82 if (major > 4) {
83 throw new IllegalArgumentException();
84 }
85 if (major == 4 && minor > 0) {
86 throw new IllegalArgumentException();
87 }
88 this.versionMajor = major;
89 this.versionMinor = minor;
90 this.constantPool = new ConstantPool();
91 this.buffer = ByteBuffer.allocateDirect(256 * 1024);
92 this.channel = channel;
93 writeVersion();
94 }
95
96 @SuppressWarnings("all")
97 public final void print(Graph graph, Map<? extends Object, ? extends Object> properties, int id, String format, Object... args) throws IOException {
98 writeByte(BEGIN_GRAPH);
99 if (versionMajor >= 3) {
100 writeInt(id);
101 writeString(format);
102 writeInt(args.length);
103 for (Object a : args) {
104 writePropertyObject(graph, a);
105 }
106 } else {
107 writePoolObject(formatTitle(graph, id, format, args));
108 }
109 writeGraph(graph, properties);
110 flush();
111 }
112
113 public final void beginGroup(Graph noGraph, String name, String shortName, ResolvedJavaMethod method, int bci, Map<? extends Object, ? extends Object> properties) throws IOException {
114 writeByte(BEGIN_GROUP);
115 writePoolObject(name);
120 }
121
122 public final void endGroup() throws IOException {
123 writeByte(CLOSE_GROUP);
124 }
125
126 @Override
127 public final void close() {
128 try {
129 flush();
130 channel.close();
131 } catch (IOException ex) {
132 throw new Error(ex);
133 }
134 }
135
136 protected abstract Graph findGraph(Graph current, Object obj);
137
138 protected abstract ResolvedJavaMethod findMethod(Object obj);
139
140 protected abstract NodeClass findNodeClass(Object obj);
141
142 /**
143 * Find a Java class. The returned object must be acceptable by
144 * {@link #findJavaTypeName(java.lang.Object)} and return valid name for the class.
145 *
146 * @param clazz node class object
147 * @return object representing the class, for example {@link Class}
148 */
149 protected abstract Object findJavaClass(NodeClass clazz);
150
151 protected abstract Object findEnumClass(Object enumValue);
152
153 protected abstract String findNameTemplate(NodeClass clazz);
154
155 protected abstract Edges findClassEdges(NodeClass nodeClass, boolean dumpInputs);
156
157 protected abstract int findNodeId(Node n);
158
159 protected abstract void findExtraNodes(Node node, Collection<? super Node> extraNodes);
160
161 protected abstract boolean hasPredecessor(Node node);
162
222
223 protected abstract NodeSourcePosition findNodeSourcePosition(Object object);
224
225 protected abstract ResolvedJavaMethod findNodeSourcePositionMethod(NodeSourcePosition pos);
226
227 protected abstract NodeSourcePosition findNodeSourcePositionCaller(NodeSourcePosition pos);
228
229 protected abstract int findNodeSourcePositionBCI(NodeSourcePosition pos);
230
231 protected abstract StackTraceElement findMethodStackTraceElement(ResolvedJavaMethod method, int bci, NodeSourcePosition pos);
232
233 private void writeVersion() throws IOException {
234 writeBytesRaw(MAGIC_BYTES);
235 writeByte(versionMajor);
236 writeByte(versionMinor);
237 }
238
239 private void flush() throws IOException {
240 buffer.flip();
241 /*
242 * Try not to let interrupted threads aborting the write. There's still a race here but an
243 * interrupt that's been pending for a long time shouldn't stop this writing.
244 */
245 boolean interrupted = Thread.interrupted();
246 try {
247 channel.write(buffer);
248 } finally {
249 if (interrupted) {
250 Thread.currentThread().interrupt();
251 }
252 }
253 buffer.compact();
254 }
255
256 private void ensureAvailable(int i) throws IOException {
257 assert buffer.capacity() >= i : "Can not make " + i + " bytes available, buffer is too small";
258 while (buffer.remaining() < i) {
259 flush();
260 }
261 }
262
321 writeInt(b.length);
322 int sizeInBytes = b.length * 4;
323 ensureAvailable(sizeInBytes);
324 buffer.asIntBuffer().put(b);
325 buffer.position(buffer.position() + sizeInBytes);
326 }
327 }
328
329 private void writeDoubles(double[] b) throws IOException {
330 if (b == null) {
331 writeInt(-1);
332 } else {
333 writeInt(b.length);
334 int sizeInBytes = b.length * 8;
335 ensureAvailable(sizeInBytes);
336 buffer.asDoubleBuffer().put(b);
337 buffer.position(buffer.position() + sizeInBytes);
338 }
339 }
340
341 private void writePoolObject(Object object) throws IOException {
342 if (object == null) {
343 writeByte(POOL_NULL);
344 return;
345 }
346 Character id = constantPool.get(object);
347 if (id == null) {
348 addPoolEntry(object);
349 } else {
350 if (object instanceof Enum<?> || findEnumOrdinal(object) >= 0) {
351 writeByte(POOL_ENUM);
352 } else if (object instanceof Class<?> || findJavaTypeName(object) != null) {
353 writeByte(POOL_CLASS);
354 } else if (findJavaField(object) != null) {
355 writeByte(POOL_FIELD);
356 } else if (findSignature(object) != null) {
357 writeByte(POOL_SIGNATURE);
358 } else if (versionMajor >= 4 && findNodeSourcePosition(object) != null) {
359 writeByte(POOL_NODE_SOURCE_POSITION);
360 } else {
361 if (findNodeClass(object) != null) {
362 writeByte(POOL_NODE_CLASS);
363 } else if (findMethod(object) != null) {
364 writeByte(POOL_METHOD);
365 } else {
366 writeByte(POOL_STRING);
367 }
368 }
369 writeShort(id.charValue());
370 }
371 }
372
373 private void writeGraph(Graph graph, Map<? extends Object, ? extends Object> properties) throws IOException {
374 writeProperties(graph, properties);
375 writeNodes(graph);
376 writeBlocks(findBlocks(graph), graph);
377 }
378
379 private void writeNodes(Graph info) throws IOException {
380 Map<String, Object> props = new HashMap<>();
381
382 final int size = findNodesCount(info);
383 writeInt(size);
384 int cnt = 0;
385 for (Node node : findNodes(info)) {
386 NodeClass nodeClass = findNodeClass(node);
387 if (nodeClass == null) {
388 throw new IOException("No class for " + node);
389 }
390 findNodeProperties(node, props, info);
391
392 writeInt(findNodeId(node));
393 writePoolObject(nodeClass);
394 writeByte(hasPredecessor(node) ? 1 : 0);
395 writeProperties(info, props);
396 writeEdges(info, node, true);
397 writeEdges(info, node, false);
398
399 props.clear();
400 cnt++;
401 }
402 if (size != cnt) {
403 throw new IOException("Expecting " + size + " nodes, but found " + cnt);
404 }
405 }
406
407 private void writeEdges(Graph graph, Node node, boolean dumpInputs) throws IOException {
408 NodeClass clazz = findNodeClass(node);
409 Edges edges = findClassEdges(clazz, dumpInputs);
410 int size = findSize(edges);
411 for (int i = 0; i < size; i++) {
412 Collection<? extends Node> list = findNodes(graph, node, edges, i);
413 if (isDirect(edges, i)) {
414 if (list != null && list.size() != 1) {
415 throw new IOException("Edge " + i + " in " + edges + " is direct, but list isn't singleton: " + list);
416 }
417 Node n = null;
418 if (list != null && !list.isEmpty()) {
419 n = list.iterator().next();
420 }
421 writeNodeRef(n);
422 } else {
423 if (list == null) {
424 writeShort((char) 0);
425 } else {
426 int listSize = list.size();
427 assert listSize == ((char) listSize);
428 writeShort((char) listSize);
429 for (Node edge : list) {
430 writeNodeRef(edge);
431 }
432 }
433 }
434 }
435 }
436
437 private void writeNodeRef(Node node) throws IOException {
438 writeInt(findNodeId(node));
439 }
440
441 private void writeBlocks(Collection<? extends Block> blocks, Graph info) throws IOException {
442 if (blocks != null) {
443 for (Block block : blocks) {
444 Collection<? extends Node> nodes = findBlockNodes(info, block);
445 if (nodes == null) {
446 writeInt(0);
447 return;
448 }
449 }
450 writeInt(blocks.size());
451 for (Block block : blocks) {
452 Collection<? extends Node> nodes = findBlockNodes(info, block);
453 writeInt(findBlockId(block));
454 writeInt(nodes.size());
455 for (Node node : nodes) {
456 writeInt(findNodeId(node));
463 }
464 } else {
465 writeInt(0);
466 }
467 }
468
469 private void writeEdgesInfo(NodeClass nodeClass, boolean dumpInputs) throws IOException {
470 Edges edges = findClassEdges(nodeClass, dumpInputs);
471 int size = findSize(edges);
472 writeShort((char) size);
473 for (int i = 0; i < size; i++) {
474 writeByte(isDirect(edges, i) ? 0 : 1);
475 writePoolObject(findName(edges, i));
476 if (dumpInputs) {
477 writePoolObject(findType(edges, i));
478 }
479 }
480 }
481
482 @SuppressWarnings("all")
483 private void addPoolEntry(Object object) throws IOException {
484 ResolvedJavaField field;
485 String typeName;
486 Signature signature;
487 NodeSourcePosition pos;
488 int enumOrdinal;
489 char index = constantPool.add(object);
490 writeByte(POOL_NEW);
491 writeShort(index);
492 if ((typeName = findJavaTypeName(object)) != null) {
493 writeByte(POOL_CLASS);
494 writeString(typeName);
495 String[] enumValueNames = findEnumTypeValues(object);
496 if (enumValueNames != null) {
497 writeByte(ENUM_KLASS);
498 writeInt(enumValueNames.length);
499 for (String o : enumValueNames) {
500 writePoolObject(o);
501 }
502 } else {
503 writeByte(KLASS);
504 }
505 } else if ((enumOrdinal = findEnumOrdinal(object)) >= 0) {
506 writeByte(POOL_ENUM);
507 writePoolObject(findEnumClass(object));
508 writeInt(enumOrdinal);
509 } else if ((field = findJavaField(object)) != null) {
510 writeByte(POOL_FIELD);
511 writePoolObject(findFieldDeclaringClass(field));
512 writePoolObject(findFieldName(field));
513 writePoolObject(findFieldTypeName(field));
514 writeInt(findFieldModifiers(field));
515 } else if ((signature = findSignature(object)) != null) {
516 writeByte(POOL_SIGNATURE);
517 int args = findSignatureParameterCount(signature);
518 writeShort((char) args);
519 for (int i = 0; i < args; i++) {
520 writePoolObject(findSignatureParameterTypeName(signature, i));
521 }
522 writePoolObject(findSignatureReturnTypeName(signature));
523 } else if (versionMajor >= 4 && (pos = findNodeSourcePosition(object)) != null) {
524 writeByte(POOL_NODE_SOURCE_POSITION);
525 ResolvedJavaMethod method = findNodeSourcePositionMethod(pos);
526 writePoolObject(method);
527 final int bci = findNodeSourcePositionBCI(pos);
528 writeInt(bci);
529 StackTraceElement ste = findMethodStackTraceElement(method, bci, pos);
530 if (ste != null && ste.getFileName() != null) {
531 writePoolObject(ste.getFileName());
532 writeInt(ste.getLineNumber());
533 } else {
534 writePoolObject(null);
535 }
536 writePoolObject(findNodeSourcePositionCaller(pos));
537 } else {
538 NodeClass nodeClass = findNodeClass(object);
539 if (nodeClass != null) {
540 writeByte(POOL_NODE_CLASS);
541 final Object clazz = findJavaClass(nodeClass);
542 if (versionMajor >= 3) {
543 writePoolObject(clazz);
544 writeString(findNameTemplate(nodeClass));
545 } else {
546 writeString(((Class<?>) clazz).getSimpleName());
547 String nameTemplate = findNameTemplate(nodeClass);
548 writeString(nameTemplate);
549 }
550 writeEdgesInfo(nodeClass, true);
551 writeEdgesInfo(nodeClass, false);
552 return;
553 }
554 ResolvedJavaMethod method = findMethod(object);
555 if (method == null) {
556 writeByte(POOL_STRING);
557 writeString(object.toString());
558 return;
559 }
560 writeByte(POOL_METHOD);
561 writePoolObject(findMethodDeclaringClass(method));
562 writePoolObject(findMethodName(method));
563 writePoolObject(findMethodSignature(method));
564 writeInt(findMethodModifiers(method));
565 writeBytes(findMethodCode(method));
566 }
567 }
568
569 private void writePropertyObject(Graph graph, Object obj) throws IOException {
570 if (obj instanceof Integer) {
571 writeByte(PROPERTY_INT);
572 writeInt(((Integer) obj).intValue());
573 } else if (obj instanceof Long) {
574 writeByte(PROPERTY_LONG);
575 writeLong(((Long) obj).longValue());
576 } else if (obj instanceof Double) {
577 writeByte(PROPERTY_DOUBLE);
|
35
36 abstract class GraphProtocol<Graph, Node, NodeClass, Edges, Block, ResolvedJavaMethod, ResolvedJavaField, Signature, NodeSourcePosition> implements Closeable {
37 private static final Charset UTF8 = Charset.forName("UTF-8");
38
39 private static final int CONSTANT_POOL_MAX_SIZE = 8000;
40
41 private static final int BEGIN_GROUP = 0x00;
42 private static final int BEGIN_GRAPH = 0x01;
43 private static final int CLOSE_GROUP = 0x02;
44
45 private static final int POOL_NEW = 0x00;
46 private static final int POOL_STRING = 0x01;
47 private static final int POOL_ENUM = 0x02;
48 private static final int POOL_CLASS = 0x03;
49 private static final int POOL_METHOD = 0x04;
50 private static final int POOL_NULL = 0x05;
51 private static final int POOL_NODE_CLASS = 0x06;
52 private static final int POOL_FIELD = 0x07;
53 private static final int POOL_SIGNATURE = 0x08;
54 private static final int POOL_NODE_SOURCE_POSITION = 0x09;
55 private static final int POOL_NODE = 0x0a;
56
57 private static final int PROPERTY_POOL = 0x00;
58 private static final int PROPERTY_INT = 0x01;
59 private static final int PROPERTY_LONG = 0x02;
60 private static final int PROPERTY_DOUBLE = 0x03;
61 private static final int PROPERTY_FLOAT = 0x04;
62 private static final int PROPERTY_TRUE = 0x05;
63 private static final int PROPERTY_FALSE = 0x06;
64 private static final int PROPERTY_ARRAY = 0x07;
65 private static final int PROPERTY_SUBGRAPH = 0x08;
66
67 private static final int KLASS = 0x00;
68 private static final int ENUM_KLASS = 0x01;
69
70 private static final byte[] MAGIC_BYTES = {'B', 'I', 'G', 'V'};
71
72 private final ConstantPool constantPool;
73 private final ByteBuffer buffer;
74 private final WritableByteChannel channel;
75 final int versionMajor;
76 final int versionMinor;
77
78 GraphProtocol(WritableByteChannel channel, int major, int minor) throws IOException {
79 if (major > 5 || (major == 5 && minor > 0)) {
80 throw new IllegalArgumentException("Unrecognized version " + major + "." + minor);
81 }
82 this.versionMajor = major;
83 this.versionMinor = minor;
84 this.constantPool = new ConstantPool();
85 this.buffer = ByteBuffer.allocateDirect(256 * 1024);
86 this.channel = channel;
87 writeVersion();
88 }
89
90 GraphProtocol(GraphProtocol<?, ?, ?, ?, ?, ?, ?, ?, ?> parent) {
91 this.versionMajor = parent.versionMajor;
92 this.versionMinor = parent.versionMinor;
93 this.constantPool = parent.constantPool;
94 this.buffer = parent.buffer;
95 this.channel = parent.channel;
96 }
97
98 @SuppressWarnings("all")
99 public final void print(Graph graph, Map<? extends Object, ? extends Object> properties, int id, String format, Object... args) throws IOException {
100 writeByte(BEGIN_GRAPH);
101 if (versionMajor >= 3) {
102 writeInt(id);
103 writeString(format);
104 writeInt(args.length);
105 for (Object a : args) {
106 writePropertyObject(graph, a);
107 }
108 } else {
109 writePoolObject(formatTitle(graph, id, format, args));
110 }
111 writeGraph(graph, properties);
112 flush();
113 }
114
115 public final void beginGroup(Graph noGraph, String name, String shortName, ResolvedJavaMethod method, int bci, Map<? extends Object, ? extends Object> properties) throws IOException {
116 writeByte(BEGIN_GROUP);
117 writePoolObject(name);
122 }
123
124 public final void endGroup() throws IOException {
125 writeByte(CLOSE_GROUP);
126 }
127
128 @Override
129 public final void close() {
130 try {
131 flush();
132 channel.close();
133 } catch (IOException ex) {
134 throw new Error(ex);
135 }
136 }
137
138 protected abstract Graph findGraph(Graph current, Object obj);
139
140 protected abstract ResolvedJavaMethod findMethod(Object obj);
141
142 /**
143 * Attempts to recognize the provided object as a node. Used to encode it with
144 * {@link #POOL_NODE} pool type.
145 *
146 * @param obj any object
147 * @return <code>null</code> if it is not a node object, non-null otherwise
148 */
149 protected abstract Node findNode(Object obj);
150
151 /**
152 * Determines whether the provided object is node class or not.
153 *
154 * @param obj object to check
155 * @return {@code null} if {@code obj} does not represent a NodeClass otherwise the NodeClass
156 * represented by {@code obj}
157 */
158 protected abstract NodeClass findNodeClass(Object obj);
159
160 /**
161 * Returns the NodeClass for a given Node {@code obj}.
162 *
163 * @param obj instance of node
164 * @return non-{@code null} instance of the node's class object
165 */
166 protected abstract NodeClass findClassForNode(Node obj);
167
168 /**
169 * Find a Java class. The returned object must be acceptable by
170 * {@link #findJavaTypeName(java.lang.Object)} and return valid name for the class.
171 *
172 * @param clazz node class object
173 * @return object representing the class, for example {@link Class}
174 */
175 protected abstract Object findJavaClass(NodeClass clazz);
176
177 protected abstract Object findEnumClass(Object enumValue);
178
179 protected abstract String findNameTemplate(NodeClass clazz);
180
181 protected abstract Edges findClassEdges(NodeClass nodeClass, boolean dumpInputs);
182
183 protected abstract int findNodeId(Node n);
184
185 protected abstract void findExtraNodes(Node node, Collection<? super Node> extraNodes);
186
187 protected abstract boolean hasPredecessor(Node node);
188
248
249 protected abstract NodeSourcePosition findNodeSourcePosition(Object object);
250
251 protected abstract ResolvedJavaMethod findNodeSourcePositionMethod(NodeSourcePosition pos);
252
253 protected abstract NodeSourcePosition findNodeSourcePositionCaller(NodeSourcePosition pos);
254
255 protected abstract int findNodeSourcePositionBCI(NodeSourcePosition pos);
256
257 protected abstract StackTraceElement findMethodStackTraceElement(ResolvedJavaMethod method, int bci, NodeSourcePosition pos);
258
259 private void writeVersion() throws IOException {
260 writeBytesRaw(MAGIC_BYTES);
261 writeByte(versionMajor);
262 writeByte(versionMinor);
263 }
264
265 private void flush() throws IOException {
266 buffer.flip();
267 /*
268 * Try not to let interrupted threads abort the write. There's still a race here but an
269 * interrupt that's been pending for a long time shouldn't stop this writing.
270 */
271 boolean interrupted = Thread.interrupted();
272 try {
273 channel.write(buffer);
274 } finally {
275 if (interrupted) {
276 Thread.currentThread().interrupt();
277 }
278 }
279 buffer.compact();
280 }
281
282 private void ensureAvailable(int i) throws IOException {
283 assert buffer.capacity() >= i : "Can not make " + i + " bytes available, buffer is too small";
284 while (buffer.remaining() < i) {
285 flush();
286 }
287 }
288
347 writeInt(b.length);
348 int sizeInBytes = b.length * 4;
349 ensureAvailable(sizeInBytes);
350 buffer.asIntBuffer().put(b);
351 buffer.position(buffer.position() + sizeInBytes);
352 }
353 }
354
355 private void writeDoubles(double[] b) throws IOException {
356 if (b == null) {
357 writeInt(-1);
358 } else {
359 writeInt(b.length);
360 int sizeInBytes = b.length * 8;
361 ensureAvailable(sizeInBytes);
362 buffer.asDoubleBuffer().put(b);
363 buffer.position(buffer.position() + sizeInBytes);
364 }
365 }
366
367 private void writePoolObject(Object obj) throws IOException {
368 Object object = obj;
369 if (object == null) {
370 writeByte(POOL_NULL);
371 return;
372 }
373 Character id = constantPool.get(object);
374 if (id == null) {
375 addPoolEntry(object);
376 } else {
377 if (findJavaField(object) != null) {
378 writeByte(POOL_FIELD);
379 } else if (findSignature(object) != null) {
380 writeByte(POOL_SIGNATURE);
381 } else if (versionMajor >= 4 && findNodeSourcePosition(object) != null) {
382 writeByte(POOL_NODE_SOURCE_POSITION);
383 } else {
384 final Node node = findNode(object);
385 if (versionMajor == 4 && node != null) {
386 object = classForNode(node);
387 }
388 if (findNodeClass(object) != null) {
389 writeByte(POOL_NODE_CLASS);
390 } else if (versionMajor >= 5 && node != null) {
391 writeByte(POOL_NODE);
392 } else if (findMethod(object) != null) {
393 writeByte(POOL_METHOD);
394 } else {
395 if (object instanceof Enum<?> || findEnumOrdinal(object) >= 0) {
396 writeByte(POOL_ENUM);
397 } else if (object instanceof Class<?> || findJavaTypeName(object) != null) {
398 writeByte(POOL_CLASS);
399 } else {
400 writeByte(POOL_STRING);
401 }
402 }
403 }
404 writeShort(id.charValue());
405 }
406 }
407
408 private void writeGraph(Graph graph, Map<? extends Object, ? extends Object> properties) throws IOException {
409 writeProperties(graph, properties);
410 writeNodes(graph);
411 writeBlocks(findBlocks(graph), graph);
412 }
413
414 private void writeNodes(Graph info) throws IOException {
415 Map<String, Object> props = new HashMap<>();
416
417 final int size = findNodesCount(info);
418 writeInt(size);
419 int cnt = 0;
420 for (Node node : findNodes(info)) {
421 NodeClass nodeClass = classForNode(node);
422 findNodeProperties(node, props, info);
423
424 writeInt(findNodeId(node));
425 writePoolObject(nodeClass);
426 writeByte(hasPredecessor(node) ? 1 : 0);
427 writeProperties(info, props);
428 writeEdges(info, node, true);
429 writeEdges(info, node, false);
430
431 props.clear();
432 cnt++;
433 }
434 if (size != cnt) {
435 throw new IOException("Expecting " + size + " nodes, but found " + cnt);
436 }
437 }
438
439 private void writeEdges(Graph graph, Node node, boolean dumpInputs) throws IOException {
440 NodeClass clazz = classForNode(node);
441 Edges edges = findClassEdges(clazz, dumpInputs);
442 int size = findSize(edges);
443 for (int i = 0; i < size; i++) {
444 Collection<? extends Node> list = findNodes(graph, node, edges, i);
445 if (isDirect(edges, i)) {
446 if (list != null && list.size() != 1) {
447 throw new IOException("Edge " + i + " in " + edges + " is direct, but list isn't singleton: " + list);
448 }
449 Node n = null;
450 if (list != null && !list.isEmpty()) {
451 n = list.iterator().next();
452 }
453 writeNodeRef(n);
454 } else {
455 if (list == null) {
456 writeShort((char) 0);
457 } else {
458 int listSize = list.size();
459 assert listSize == ((char) listSize);
460 writeShort((char) listSize);
461 for (Node edge : list) {
462 writeNodeRef(edge);
463 }
464 }
465 }
466 }
467 }
468
469 private NodeClass classForNode(Node node) throws IOException {
470 NodeClass clazz = findClassForNode(node);
471 if (clazz == null) {
472 throw new IOException("No class for " + node);
473 }
474 return clazz;
475 }
476
477 private void writeNodeRef(Node node) throws IOException {
478 writeInt(findNodeId(node));
479 }
480
481 private void writeBlocks(Collection<? extends Block> blocks, Graph info) throws IOException {
482 if (blocks != null) {
483 for (Block block : blocks) {
484 Collection<? extends Node> nodes = findBlockNodes(info, block);
485 if (nodes == null) {
486 writeInt(0);
487 return;
488 }
489 }
490 writeInt(blocks.size());
491 for (Block block : blocks) {
492 Collection<? extends Node> nodes = findBlockNodes(info, block);
493 writeInt(findBlockId(block));
494 writeInt(nodes.size());
495 for (Node node : nodes) {
496 writeInt(findNodeId(node));
503 }
504 } else {
505 writeInt(0);
506 }
507 }
508
509 private void writeEdgesInfo(NodeClass nodeClass, boolean dumpInputs) throws IOException {
510 Edges edges = findClassEdges(nodeClass, dumpInputs);
511 int size = findSize(edges);
512 writeShort((char) size);
513 for (int i = 0; i < size; i++) {
514 writeByte(isDirect(edges, i) ? 0 : 1);
515 writePoolObject(findName(edges, i));
516 if (dumpInputs) {
517 writePoolObject(findType(edges, i));
518 }
519 }
520 }
521
522 @SuppressWarnings("all")
523 private void addPoolEntry(Object obj) throws IOException {
524 Object object = obj;
525 ResolvedJavaField field;
526 String typeName;
527 Signature signature;
528 NodeSourcePosition pos;
529 int enumOrdinal;
530 char index = constantPool.add(object);
531 writeByte(POOL_NEW);
532 writeShort(index);
533 if ((field = findJavaField(object)) != null) {
534 writeByte(POOL_FIELD);
535 writePoolObject(findFieldDeclaringClass(field));
536 writePoolObject(findFieldName(field));
537 writePoolObject(findFieldTypeName(field));
538 writeInt(findFieldModifiers(field));
539 } else if ((signature = findSignature(object)) != null) {
540 writeByte(POOL_SIGNATURE);
541 int args = findSignatureParameterCount(signature);
542 writeShort((char) args);
543 for (int i = 0; i < args; i++) {
544 writePoolObject(findSignatureParameterTypeName(signature, i));
545 }
546 writePoolObject(findSignatureReturnTypeName(signature));
547 } else if (versionMajor >= 4 && (pos = findNodeSourcePosition(object)) != null) {
548 writeByte(POOL_NODE_SOURCE_POSITION);
549 ResolvedJavaMethod method = findNodeSourcePositionMethod(pos);
550 writePoolObject(method);
551 final int bci = findNodeSourcePositionBCI(pos);
552 writeInt(bci);
553 StackTraceElement ste = findMethodStackTraceElement(method, bci, pos);
554 if (ste != null && ste.getFileName() != null) {
555 writePoolObject(ste.getFileName());
556 writeInt(ste.getLineNumber());
557 } else {
558 writePoolObject(null);
559 }
560 writePoolObject(findNodeSourcePositionCaller(pos));
561 } else {
562 Node node = findNode(object);
563 if (node != null) {
564 if (versionMajor >= 5) {
565 writeByte(POOL_NODE);
566 writeInt(findNodeId(node));
567 writePoolObject(classForNode(node));
568 return;
569 }
570 if (versionMajor == 4) {
571 object = classForNode(node);
572 }
573 }
574 NodeClass nodeClass = findNodeClass(object);
575 if (nodeClass != null) {
576 writeByte(POOL_NODE_CLASS);
577 final Object clazz = findJavaClass(nodeClass);
578 if (versionMajor >= 3) {
579 writePoolObject(clazz);
580 writeString(findNameTemplate(nodeClass));
581 } else {
582 writeString(((Class<?>) clazz).getSimpleName());
583 String nameTemplate = findNameTemplate(nodeClass);
584 writeString(nameTemplate);
585 }
586 writeEdgesInfo(nodeClass, true);
587 writeEdgesInfo(nodeClass, false);
588 return;
589 }
590 ResolvedJavaMethod method = findMethod(object);
591 if (method == null) {
592 if ((typeName = findJavaTypeName(object)) != null) {
593 writeByte(POOL_CLASS);
594 writeString(typeName);
595 String[] enumValueNames = findEnumTypeValues(object);
596 if (enumValueNames != null) {
597 writeByte(ENUM_KLASS);
598 writeInt(enumValueNames.length);
599 for (String o : enumValueNames) {
600 writePoolObject(o);
601 }
602 } else {
603 writeByte(KLASS);
604 }
605 } else if ((enumOrdinal = findEnumOrdinal(object)) >= 0) {
606 writeByte(POOL_ENUM);
607 writePoolObject(findEnumClass(object));
608 writeInt(enumOrdinal);
609 } else {
610 writeByte(POOL_STRING);
611 writeString(object.toString());
612 }
613 return;
614 }
615 writeByte(POOL_METHOD);
616 writePoolObject(findMethodDeclaringClass(method));
617 writePoolObject(findMethodName(method));
618 writePoolObject(findMethodSignature(method));
619 writeInt(findMethodModifiers(method));
620 writeBytes(findMethodCode(method));
621 }
622 }
623
624 private void writePropertyObject(Graph graph, Object obj) throws IOException {
625 if (obj instanceof Integer) {
626 writeByte(PROPERTY_INT);
627 writeInt(((Integer) obj).intValue());
628 } else if (obj instanceof Long) {
629 writeByte(PROPERTY_LONG);
630 writeLong(((Long) obj).longValue());
631 } else if (obj instanceof Double) {
632 writeByte(PROPERTY_DOUBLE);
|