61 private static final int POOL_NODE = 0x0a; 62 63 private static final int PROPERTY_POOL = 0x00; 64 private static final int PROPERTY_INT = 0x01; 65 private static final int PROPERTY_LONG = 0x02; 66 private static final int PROPERTY_DOUBLE = 0x03; 67 private static final int PROPERTY_FLOAT = 0x04; 68 private static final int PROPERTY_TRUE = 0x05; 69 private static final int PROPERTY_FALSE = 0x06; 70 private static final int PROPERTY_ARRAY = 0x07; 71 private static final int PROPERTY_SUBGRAPH = 0x08; 72 73 private static final int KLASS = 0x00; 74 private static final int ENUM_KLASS = 0x01; 75 76 private static final byte[] MAGIC_BYTES = {'B', 'I', 'G', 'V'}; 77 78 private final ConstantPool constantPool; 79 private final ByteBuffer buffer; 80 private final WritableByteChannel channel; 81 final int versionMajor; 82 final int versionMinor; 83 84 GraphProtocol(WritableByteChannel channel, int major, int minor) throws IOException { 85 if (major > 6 || (major == 6 && minor > 0)) { 86 throw new IllegalArgumentException("Unrecognized version " + major + "." + minor); 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 GraphProtocol(GraphProtocol<?, ?, ?, ?, ?, ?, ?, ?, ?, ?> parent) { 97 this.versionMajor = parent.versionMajor; 98 this.versionMinor = parent.versionMinor; 99 this.constantPool = parent.constantPool; 100 this.buffer = parent.buffer; 101 this.channel = parent.channel; 102 } 103 104 @SuppressWarnings("all") 105 public final void print(Graph graph, Map<? extends Object, ? extends Object> properties, int id, String format, Object... args) throws IOException { 106 writeByte(BEGIN_GRAPH); 107 if (versionMajor >= 3) { 108 writeInt(id); 109 writeString(format); 110 writeInt(args.length); 111 for (Object a : args) { 112 writePropertyObject(graph, a); 113 } 114 } else { 115 writePoolObject(formatTitle(graph, id, format, args)); 116 } 117 writeGraph(graph, properties); 118 flush(); 119 } 120 121 public final void beginGroup(Graph noGraph, String name, String shortName, ResolvedJavaMethod method, int bci, Map<? extends Object, ? extends Object> properties) throws IOException { 122 writeByte(BEGIN_GROUP); 123 writePoolObject(name); 124 writePoolObject(shortName); 125 writePoolObject(method); 126 writeInt(bci); 127 writeProperties(noGraph, properties); 128 } 129 130 public final void endGroup() throws IOException { 131 writeByte(CLOSE_GROUP); 132 } 133 134 @Override 135 public final void close() { 136 try { 137 flush(); 138 channel.close(); 139 } catch (IOException ex) { 140 throw new Error(ex); 141 } 142 } 143 144 protected abstract Graph findGraph(Graph current, Object obj); 145 146 protected abstract ResolvedJavaMethod findMethod(Object obj); 147 148 /** 149 * Attempts to recognize the provided object as a node. Used to encode it with 150 * {@link #POOL_NODE} pool type. 151 * 263 protected abstract Iterable<Location> findLocation(ResolvedJavaMethod method, int bci, NodeSourcePosition pos); 264 265 protected abstract String findLocationFile(Location loc) throws IOException; 266 267 protected abstract int findLocationLine(Location loc); 268 269 protected abstract URI findLocationURI(Location loc) throws URISyntaxException; 270 271 protected abstract String findLocationLanguage(Location loc); 272 273 protected abstract int findLocationStart(Location loc); 274 275 protected abstract int findLocationEnd(Location loc); 276 277 private void writeVersion() throws IOException { 278 writeBytesRaw(MAGIC_BYTES); 279 writeByte(versionMajor); 280 writeByte(versionMinor); 281 } 282 283 private void flush() throws IOException { 284 buffer.flip(); 285 /* 286 * Try not to let interrupted threads abort the write. There's still a race here but an 287 * interrupt that's been pending for a long time shouldn't stop this writing. 288 */ 289 boolean interrupted = Thread.interrupted(); 290 try { 291 channel.write(buffer); 292 } finally { 293 if (interrupted) { 294 Thread.currentThread().interrupt(); 295 } 296 } 297 buffer.compact(); 298 } 299 300 private void ensureAvailable(int i) throws IOException { 301 assert buffer.capacity() >= i : "Can not make " + i + " bytes available, buffer is too small"; 302 while (buffer.remaining() < i) { 341 342 private void writeBytes(byte[] b) throws IOException { 343 if (b == null) { 344 writeInt(-1); 345 } else { 346 writeInt(b.length); 347 writeBytesRaw(b); 348 } 349 } 350 351 private void writeBytesRaw(byte[] b) throws IOException { 352 int bytesWritten = 0; 353 while (bytesWritten < b.length) { 354 int toWrite = Math.min(b.length - bytesWritten, buffer.capacity()); 355 ensureAvailable(toWrite); 356 buffer.put(b, bytesWritten, toWrite); 357 bytesWritten += toWrite; 358 } 359 } 360 361 private void writeInts(int[] b) throws IOException { 362 if (b == null) { 363 writeInt(-1); 364 } else { 365 writeInt(b.length); 366 int sizeInBytes = b.length * 4; 367 ensureAvailable(sizeInBytes); 368 buffer.asIntBuffer().put(b); 369 buffer.position(buffer.position() + sizeInBytes); 370 } 371 } 372 373 private void writeDoubles(double[] b) throws IOException { 374 if (b == null) { 375 writeInt(-1); 376 } else { 377 writeInt(b.length); 378 int sizeInBytes = b.length * 8; 379 ensureAvailable(sizeInBytes); 380 buffer.asDoubleBuffer().put(b); 800 @Override 801 protected boolean removeEldestEntry(java.util.Map.Entry<Object, Character> eldest) { 802 if (size() > CONSTANT_POOL_MAX_SIZE) { 803 availableIds.addFirst(eldest.getValue()); 804 return true; 805 } 806 return false; 807 } 808 809 private Character nextAvailableId() { 810 if (!availableIds.isEmpty()) { 811 return availableIds.removeFirst(); 812 } 813 return nextId++; 814 } 815 816 public char add(Object obj) { 817 Character id = nextAvailableId(); 818 put(obj, id); 819 return id; 820 } 821 } 822 823 } | 61 private static final int POOL_NODE = 0x0a; 62 63 private static final int PROPERTY_POOL = 0x00; 64 private static final int PROPERTY_INT = 0x01; 65 private static final int PROPERTY_LONG = 0x02; 66 private static final int PROPERTY_DOUBLE = 0x03; 67 private static final int PROPERTY_FLOAT = 0x04; 68 private static final int PROPERTY_TRUE = 0x05; 69 private static final int PROPERTY_FALSE = 0x06; 70 private static final int PROPERTY_ARRAY = 0x07; 71 private static final int PROPERTY_SUBGRAPH = 0x08; 72 73 private static final int KLASS = 0x00; 74 private static final int ENUM_KLASS = 0x01; 75 76 private static final byte[] MAGIC_BYTES = {'B', 'I', 'G', 'V'}; 77 78 private final ConstantPool constantPool; 79 private final ByteBuffer buffer; 80 private final WritableByteChannel channel; 81 private final boolean embedded; 82 final int versionMajor; 83 final int versionMinor; 84 private boolean printing; 85 86 GraphProtocol(WritableByteChannel channel, int major, int minor, boolean embedded) throws IOException { 87 if (major > 6 || (major == 6 && minor > 0)) { 88 throw new IllegalArgumentException("Unrecognized version " + major + "." + minor); 89 } 90 this.versionMajor = major; 91 this.versionMinor = minor; 92 this.constantPool = new ConstantPool(); 93 this.buffer = ByteBuffer.allocateDirect(256 * 1024); 94 this.channel = channel; 95 this.embedded = embedded; 96 if (!embedded) { 97 writeVersion(); 98 flushEmbedded(); 99 } 100 } 101 102 GraphProtocol(GraphProtocol<?, ?, ?, ?, ?, ?, ?, ?, ?, ?> parent) { 103 this.versionMajor = parent.versionMajor; 104 this.versionMinor = parent.versionMinor; 105 this.constantPool = parent.constantPool; 106 this.buffer = parent.buffer; 107 this.channel = parent.channel; 108 this.embedded = parent.embedded; 109 } 110 111 @SuppressWarnings("all") 112 public final void print(Graph graph, Map<? extends Object, ? extends Object> properties, int id, String format, Object... args) throws IOException { 113 printing = true; 114 try { 115 writeByte(BEGIN_GRAPH); 116 if (versionMajor >= 3) { 117 writeInt(id); 118 writeString(format); 119 writeInt(args.length); 120 for (Object a : args) { 121 writePropertyObject(graph, a); 122 } 123 } else { 124 writePoolObject(formatTitle(graph, id, format, args)); 125 } 126 writeGraph(graph, properties); 127 flushEmbedded(); 128 flush(); 129 } finally { 130 printing = false; 131 } 132 } 133 134 public final void beginGroup(Graph noGraph, String name, String shortName, ResolvedJavaMethod method, int bci, Map<? extends Object, ? extends Object> properties) throws IOException { 135 printing = true; 136 try { 137 writeByte(BEGIN_GROUP); 138 writePoolObject(name); 139 writePoolObject(shortName); 140 writePoolObject(method); 141 writeInt(bci); 142 writeProperties(noGraph, properties); 143 flushEmbedded(); 144 } finally { 145 printing = false; 146 } 147 } 148 149 public final void endGroup() throws IOException { 150 printing = true; 151 try { 152 writeByte(CLOSE_GROUP); 153 flushEmbedded(); 154 } finally { 155 printing = false; 156 } 157 } 158 159 final int write(ByteBuffer src) throws IOException { 160 if (printing) { 161 throw new IllegalStateException("Trying to write during graph print."); 162 } 163 constantPool.reset(); 164 return writeBytesRaw(src); 165 } 166 167 final boolean isOpen() { 168 return channel.isOpen(); 169 } 170 171 @Override 172 public final void close() { 173 try { 174 flush(); 175 channel.close(); 176 } catch (IOException ex) { 177 throw new Error(ex); 178 } 179 } 180 181 protected abstract Graph findGraph(Graph current, Object obj); 182 183 protected abstract ResolvedJavaMethod findMethod(Object obj); 184 185 /** 186 * Attempts to recognize the provided object as a node. Used to encode it with 187 * {@link #POOL_NODE} pool type. 188 * 300 protected abstract Iterable<Location> findLocation(ResolvedJavaMethod method, int bci, NodeSourcePosition pos); 301 302 protected abstract String findLocationFile(Location loc) throws IOException; 303 304 protected abstract int findLocationLine(Location loc); 305 306 protected abstract URI findLocationURI(Location loc) throws URISyntaxException; 307 308 protected abstract String findLocationLanguage(Location loc); 309 310 protected abstract int findLocationStart(Location loc); 311 312 protected abstract int findLocationEnd(Location loc); 313 314 private void writeVersion() throws IOException { 315 writeBytesRaw(MAGIC_BYTES); 316 writeByte(versionMajor); 317 writeByte(versionMinor); 318 } 319 320 private void flushEmbedded() throws IOException { 321 if (embedded) { 322 flush(); 323 constantPool.reset(); 324 } 325 } 326 327 private void flush() throws IOException { 328 buffer.flip(); 329 /* 330 * Try not to let interrupted threads abort the write. There's still a race here but an 331 * interrupt that's been pending for a long time shouldn't stop this writing. 332 */ 333 boolean interrupted = Thread.interrupted(); 334 try { 335 channel.write(buffer); 336 } finally { 337 if (interrupted) { 338 Thread.currentThread().interrupt(); 339 } 340 } 341 buffer.compact(); 342 } 343 344 private void ensureAvailable(int i) throws IOException { 345 assert buffer.capacity() >= i : "Can not make " + i + " bytes available, buffer is too small"; 346 while (buffer.remaining() < i) { 385 386 private void writeBytes(byte[] b) throws IOException { 387 if (b == null) { 388 writeInt(-1); 389 } else { 390 writeInt(b.length); 391 writeBytesRaw(b); 392 } 393 } 394 395 private void writeBytesRaw(byte[] b) throws IOException { 396 int bytesWritten = 0; 397 while (bytesWritten < b.length) { 398 int toWrite = Math.min(b.length - bytesWritten, buffer.capacity()); 399 ensureAvailable(toWrite); 400 buffer.put(b, bytesWritten, toWrite); 401 bytesWritten += toWrite; 402 } 403 } 404 405 private int writeBytesRaw(ByteBuffer b) throws IOException { 406 int limit = b.limit(); 407 int written = 0; 408 while (b.position() < limit) { 409 int toWrite = Math.min(limit - b.position(), buffer.capacity()); 410 ensureAvailable(toWrite); 411 b.limit(b.position() + toWrite); 412 try { 413 buffer.put(b); 414 written += toWrite; 415 } finally { 416 b.limit(limit); 417 } 418 } 419 return written; 420 } 421 422 private void writeInts(int[] b) throws IOException { 423 if (b == null) { 424 writeInt(-1); 425 } else { 426 writeInt(b.length); 427 int sizeInBytes = b.length * 4; 428 ensureAvailable(sizeInBytes); 429 buffer.asIntBuffer().put(b); 430 buffer.position(buffer.position() + sizeInBytes); 431 } 432 } 433 434 private void writeDoubles(double[] b) throws IOException { 435 if (b == null) { 436 writeInt(-1); 437 } else { 438 writeInt(b.length); 439 int sizeInBytes = b.length * 8; 440 ensureAvailable(sizeInBytes); 441 buffer.asDoubleBuffer().put(b); 861 @Override 862 protected boolean removeEldestEntry(java.util.Map.Entry<Object, Character> eldest) { 863 if (size() > CONSTANT_POOL_MAX_SIZE) { 864 availableIds.addFirst(eldest.getValue()); 865 return true; 866 } 867 return false; 868 } 869 870 private Character nextAvailableId() { 871 if (!availableIds.isEmpty()) { 872 return availableIds.removeFirst(); 873 } 874 return nextId++; 875 } 876 877 public char add(Object obj) { 878 Character id = nextAvailableId(); 879 put(obj, id); 880 return id; 881 } 882 883 void reset() { 884 clear(); 885 availableIds.clear(); 886 nextId = 0; 887 } 888 } 889 890 } |