1 /* 2 * Copyright (c) 2009, 2014, 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. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 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 package jdk.vm.ci.code; 24 25 import static java.util.Collections.*; 26 import static jdk.vm.ci.meta.MetaUtil.*; 27 28 import java.util.*; 29 30 import jdk.vm.ci.meta.*; 31 import jdk.vm.ci.meta.Assumptions.*; 32 33 /** 34 * Represents the output from compiling a method, including the compiled machine code, associated 35 * data and references, relocation information, deoptimization information, etc. 36 */ 37 public class CompilationResult { 38 39 /** 40 * Represents a code position with associated additional information. 41 */ 42 public abstract static class Site { 43 44 /** 45 * The position (or offset) of this site with respect to the start of the target method. 46 */ 47 public final int pcOffset; 48 49 public Site(int pos) { 50 this.pcOffset = pos; 51 } 52 53 @Override 54 public final int hashCode() { 55 throw new UnsupportedOperationException("hashCode"); 56 } 57 58 @Override 59 public String toString() { 60 return identityHashCodeString(this); 61 } 62 63 @Override 64 public abstract boolean equals(Object obj); 65 } 66 67 /** 68 * Represents an infopoint with associated debug info. Note that safepoints are also infopoints. 69 */ 70 public static class Infopoint extends Site implements Comparable<Infopoint> { 71 72 public final DebugInfo debugInfo; 73 74 public final InfopointReason reason; 75 76 public Infopoint(int pcOffset, DebugInfo debugInfo, InfopointReason reason) { 77 super(pcOffset); 78 this.debugInfo = debugInfo; 79 this.reason = reason; 80 } 81 82 @Override 83 public String toString() { 84 StringBuilder sb = new StringBuilder(); 85 sb.append(pcOffset); 86 sb.append("[<infopoint>]"); 87 appendDebugInfo(sb, debugInfo); 88 return sb.toString(); 89 } 90 91 @Override 92 public int compareTo(Infopoint o) { 93 if (pcOffset < o.pcOffset) { 94 return -1; 95 } else if (pcOffset > o.pcOffset) { 96 return 1; 97 } 98 return this.reason.compareTo(o.reason); 99 } 100 101 @Override 102 public boolean equals(Object obj) { 103 if (this == obj) { 104 return true; 105 } 106 if (obj != null && obj.getClass() == getClass()) { 107 Infopoint that = (Infopoint) obj; 108 if (this.pcOffset == that.pcOffset && Objects.equals(this.debugInfo, that.debugInfo) && Objects.equals(this.reason, that.reason)) { 109 return true; 110 } 111 } 112 return false; 113 } 114 } 115 116 public enum MetaSpaceAccessType { 117 Move, 118 Store, // store only works for compressed oops (memory <- 32bit value). Compressed oops is 119 // not supported using AOT. TODO: Look at HotSpotStoreConstantOp 120 Compare; // HotSpotCompareMemoryConstantOp, HotSpotCompareConstantOp 121 122 private MetaSpaceAccessType() { 123 } 124 } 125 126 /** 127 * Represents a meta space pointer access in the code. 128 */ 129 public static final class MetaSpaceAccess extends Infopoint { 130 131 private static final long serialVersionUID = 1701958512608684706L; 132 133 /** 134 * Metaspace reference. 135 */ 136 public final Object reference; // Object here is a HotSpotResolvedObjectType or a 137 // HotSpotMetaSpaceConstant 138 139 public final MetaSpaceAccessType type; 140 141 /** 142 * Instruction size. 143 */ 144 public final int instructionSize; 145 146 public MetaSpaceAccess(Object reference, int instructionSize, MetaSpaceAccessType type, int pcOffset, DebugInfo debugInfo) { 147 super(pcOffset, debugInfo, InfopointReason.METASPACE_ACCESS); 148 this.type = type; 149 this.reference = reference; 150 this.instructionSize = instructionSize; 151 } 152 } 153 154 /** 155 * Represents a call in the code. 156 */ 157 public static final class Call extends Infopoint { 158 159 /** 160 * The target of the call. 161 */ 162 public final InvokeTarget target; 163 164 /** 165 * The size of the call instruction. 166 */ 167 public final int size; 168 169 /** 170 * Specifies if this call is direct or indirect. A direct call has an immediate operand 171 * encoding the absolute or relative (to the call itself) address of the target. An indirect 172 * call has a register or memory operand specifying the target address of the call. 173 */ 174 public final boolean direct; 175 176 public Call(InvokeTarget target, int pcOffset, int size, boolean direct, DebugInfo debugInfo) { 177 super(pcOffset, debugInfo, InfopointReason.CALL); 178 this.size = size; 179 this.target = target; 180 this.direct = direct; 181 } 182 183 @Override 184 public boolean equals(Object obj) { 185 if (this == obj) { 186 return true; 187 } 188 if (obj instanceof Call && super.equals(obj)) { 189 Call that = (Call) obj; 190 if (this.size == that.size && this.direct == that.direct && Objects.equals(this.target, that.target)) { 191 return true; 192 } 193 } 194 return false; 195 } 196 197 @Override 198 public String toString() { 199 StringBuilder sb = new StringBuilder(); 200 sb.append(pcOffset); 201 sb.append('['); 202 sb.append(target); 203 sb.append(']'); 204 205 if (debugInfo != null) { 206 appendDebugInfo(sb, debugInfo); 207 } 208 209 return sb.toString(); 210 } 211 } 212 213 /** 214 * Represents some external data that is referenced by the code. 215 */ 216 public abstract static class Reference { 217 218 @Override 219 public abstract int hashCode(); 220 221 @Override 222 public abstract boolean equals(Object obj); 223 } 224 225 public static final class ConstantReference extends Reference { 226 227 private final VMConstant constant; 228 229 public ConstantReference(VMConstant constant) { 230 this.constant = constant; 231 } 232 233 public VMConstant getConstant() { 234 return constant; 235 } 236 237 @Override 238 public String toString() { 239 return constant.toString(); 240 } 241 242 @Override 243 public int hashCode() { 244 return constant.hashCode(); 245 } 246 247 @Override 248 public boolean equals(Object obj) { 249 if (this == obj) { 250 return true; 251 } 252 if (obj instanceof ConstantReference) { 253 ConstantReference that = (ConstantReference) obj; 254 return Objects.equals(this.constant, that.constant); 255 } 256 return false; 257 } 258 } 259 260 public static final class DataSectionReference extends Reference { 261 262 private boolean initialized; 263 private int offset; 264 265 public DataSectionReference() { 266 // will be set after the data section layout is fixed 267 offset = 0xDEADDEAD; 268 } 269 270 public int getOffset() { 271 assert initialized; 272 273 return offset; 274 } 275 276 public void setOffset(int offset) { 277 assert !initialized; 278 initialized = true; 279 280 this.offset = offset; 281 } 282 283 @Override 284 public int hashCode() { 285 return offset; 286 } 287 288 @Override 289 public boolean equals(Object obj) { 290 if (this == obj) { 291 return true; 292 } 293 if (obj instanceof DataSectionReference) { 294 DataSectionReference that = (DataSectionReference) obj; 295 return this.offset == that.offset; 296 } 297 return false; 298 } 299 } 300 301 /** 302 * Represents a code site that references some data. The associated data can be either a 303 * {@link DataSectionReference reference} to the data section, or it may be an inlined 304 * {@link JavaConstant} that needs to be patched. 305 */ 306 public static final class DataPatch extends Site { 307 308 public Reference reference; 309 public Object note; 310 311 public DataPatch(int pcOffset, Reference reference) { 312 super(pcOffset); 313 this.reference = reference; 314 this.note = null; 315 } 316 317 public DataPatch(int pcOffset, Reference reference, Object note) { 318 super(pcOffset); 319 this.reference = reference; 320 this.note = note; 321 } 322 323 @Override 324 public String toString() { 325 if (note != null) { 326 return String.format("%d[<data patch referring to %s>, note: %s]", pcOffset, reference.toString(), note.toString()); 327 } else { 328 return String.format("%d[<data patch referring to %s>]", pcOffset, reference.toString()); 329 } 330 } 331 332 @Override 333 public boolean equals(Object obj) { 334 if (this == obj) { 335 return true; 336 } 337 if (obj instanceof DataPatch) { 338 DataPatch that = (DataPatch) obj; 339 if (this.pcOffset == that.pcOffset && Objects.equals(this.reference, that.reference) && Objects.equals(this.note, that.note)) { 340 return true; 341 } 342 } 343 return false; 344 } 345 } 346 347 /** 348 * Provides extra information about instructions or data at specific positions in 349 * {@link CompilationResult#getTargetCode()}. This is optional information that can be used to 350 * enhance a disassembly of the code. 351 */ 352 public abstract static class CodeAnnotation { 353 354 public final int position; 355 356 public CodeAnnotation(int position) { 357 this.position = position; 358 } 359 360 @Override 361 public final int hashCode() { 362 throw new UnsupportedOperationException("hashCode"); 363 } 364 365 @Override 366 public String toString() { 367 return identityHashCodeString(this); 368 } 369 370 @Override 371 public abstract boolean equals(Object obj); 372 } 373 374 /** 375 * A string comment about one or more instructions at a specific position in the code. 376 */ 377 public static final class CodeComment extends CodeAnnotation { 378 379 public final String value; 380 381 public CodeComment(int position, String comment) { 382 super(position); 383 this.value = comment; 384 } 385 386 @Override 387 public boolean equals(Object obj) { 388 if (this == obj) { 389 return true; 390 } 391 if (obj instanceof CodeComment) { 392 CodeComment that = (CodeComment) obj; 393 if (this.position == that.position && this.value.equals(that.value)) { 394 return true; 395 } 396 } 397 return false; 398 } 399 400 @Override 401 public String toString() { 402 return getClass().getSimpleName() + "@" + position + ": " + value; 403 } 404 } 405 406 /** 407 * Describes a table of signed offsets embedded in the code. The offsets are relative to the 408 * starting address of the table. This type of table maybe generated when translating a 409 * multi-way branch based on a key value from a dense value set (e.g. the {@code tableswitch} 410 * JVM instruction). 411 * 412 * The table is indexed by the contiguous range of integers from {@link #low} to {@link #high} 413 * inclusive. 414 */ 415 public static final class JumpTable extends CodeAnnotation { 416 417 /** 418 * The low value in the key range (inclusive). 419 */ 420 public final int low; 421 422 /** 423 * The high value in the key range (inclusive). 424 */ 425 public final int high; 426 427 /** 428 * The size (in bytes) of each table entry. 429 */ 430 public final int entrySize; 431 432 public JumpTable(int position, int low, int high, int entrySize) { 433 super(position); 434 this.low = low; 435 this.high = high; 436 this.entrySize = entrySize; 437 } 438 439 @Override 440 public boolean equals(Object obj) { 441 if (this == obj) { 442 return true; 443 } 444 if (obj instanceof JumpTable) { 445 JumpTable that = (JumpTable) obj; 446 if (this.position == that.position && this.entrySize == that.entrySize && this.low == that.low && this.high == that.high) { 447 return true; 448 } 449 } 450 return false; 451 } 452 453 @Override 454 public String toString() { 455 return getClass().getSimpleName() + "@" + position + ": [" + low + " .. " + high + "]"; 456 } 457 } 458 459 /** 460 * Represents exception handler information for a specific code position. It includes the catch 461 * code position as well as the caught exception type. 462 */ 463 public static final class ExceptionHandler extends Site { 464 465 public final int handlerPos; 466 467 ExceptionHandler(int pcOffset, int handlerPos) { 468 super(pcOffset); 469 this.handlerPos = handlerPos; 470 } 471 472 @Override 473 public String toString() { 474 return String.format("%d[<exception edge to %d>]", pcOffset, handlerPos); 475 } 476 477 @Override 478 public boolean equals(Object obj) { 479 if (this == obj) { 480 return true; 481 } 482 if (obj instanceof ExceptionHandler) { 483 ExceptionHandler that = (ExceptionHandler) obj; 484 if (this.pcOffset == that.pcOffset && this.handlerPos == that.handlerPos) { 485 return true; 486 } 487 } 488 return false; 489 } 490 } 491 492 /** 493 * Represents a mark in the machine code that can be used by the runtime for its own purposes. A 494 * mark can reference other marks. 495 */ 496 public static final class Mark extends Site { 497 498 public final Object id; 499 500 public Mark(int pcOffset, Object id) { 501 super(pcOffset); 502 this.id = id; 503 } 504 505 @Override 506 public String toString() { 507 if (id == null) { 508 return String.format("%d[<mar>]", pcOffset); 509 } else if (id instanceof Integer) { 510 return String.format("%d[<mark with id %s>]", pcOffset, Integer.toHexString((Integer) id)); 511 } else { 512 return String.format("%d[<mark with id %s>]", pcOffset, id.toString()); 513 } 514 } 515 516 @Override 517 public boolean equals(Object obj) { 518 if (this == obj) { 519 return true; 520 } 521 if (obj instanceof Mark) { 522 Mark that = (Mark) obj; 523 if (this.pcOffset == that.pcOffset && Objects.equals(this.id, that.id)) { 524 return true; 525 } 526 } 527 return false; 528 } 529 } 530 531 private int id = -1; 532 533 /** 534 * Specifies whether this compilation is a {@code +ImmutableCode} {@code +GeneratePIC} 535 * compilation. 536 */ 537 private final boolean isImmutablePIC; 538 539 private int entryBCI = -1; 540 541 private final DataSection dataSection = new DataSection(); 542 543 private final List<Infopoint> infopoints = new ArrayList<>(); 544 private final List<DataPatch> dataPatches = new ArrayList<>(); 545 private final List<ExceptionHandler> exceptionHandlers = new ArrayList<>(); 546 private final List<Mark> marks = new ArrayList<>(); 547 548 private int totalFrameSize = -1; 549 private int customStackAreaOffset = -1; 550 551 private final String name; 552 553 /** 554 * The buffer containing the emitted machine code. 555 */ 556 private byte[] targetCode; 557 558 /** 559 * The leading number of bytes in {@link #targetCode} containing the emitted machine code. 560 */ 561 private int targetCodeSize; 562 563 private ArrayList<CodeAnnotation> annotations; 564 565 private Assumption[] assumptions; 566 567 /** 568 * The list of the methods whose bytecodes were used as input to the compilation. If 569 * {@code null}, then the compilation did not record method dependencies. Otherwise, the first 570 * element of this array is the root method of the compilation. 571 */ 572 private ResolvedJavaMethod[] methods; 573 574 private int bytecodeSize; 575 576 private boolean hasUnsafeAccess; 577 578 public CompilationResult() { 579 this(null); 580 } 581 582 public CompilationResult(String name) { 583 this.name = name; 584 this.isImmutablePIC = false; 585 } 586 587 public CompilationResult(boolean isImmutablePIC) { 588 this.name = null; 589 this.isImmutablePIC = isImmutablePIC; 590 } 591 592 @Override 593 public int hashCode() { 594 // CompilationResult instances should not be used as hash map keys 595 throw new UnsupportedOperationException("hashCode"); 596 } 597 598 @Override 599 public String toString() { 600 if (methods != null) { 601 return getClass().getName() + "[" + methods[0].format("%H.%n(%p)%r") + "]"; 602 } 603 return identityHashCodeString(this); 604 } 605 606 @Override 607 public boolean equals(Object obj) { 608 if (this == obj) { 609 return true; 610 } 611 if (obj != null && obj.getClass() == getClass()) { 612 CompilationResult that = (CompilationResult) obj; 613 // @formatter:off 614 if (this.entryBCI == that.entryBCI && 615 this.id == that.id && 616 this.customStackAreaOffset == that.customStackAreaOffset && 617 this.totalFrameSize == that.totalFrameSize && 618 this.targetCodeSize == that.targetCodeSize && 619 Objects.equals(this.name, that.name) && 620 Objects.equals(this.annotations, that.annotations) && 621 Objects.equals(this.dataSection, that.dataSection) && 622 Objects.equals(this.exceptionHandlers, that.exceptionHandlers) && 623 Objects.equals(this.dataPatches, that.dataPatches) && 624 Objects.equals(this.infopoints, that.infopoints) && 625 Objects.equals(this.marks, that.marks) && 626 Arrays.equals(this.assumptions, that.assumptions) && 627 Arrays.equals(targetCode, that.targetCode)) { 628 return true; 629 } 630 // @formatter:on 631 } 632 return false; 633 } 634 635 /** 636 * @return the compile id 637 */ 638 public int getId() { 639 return id; 640 } 641 642 /** 643 * @param id the compile id to set 644 */ 645 public void setId(int id) { 646 this.id = id; 647 } 648 649 /** 650 * @return true is this is a {@code +ImmutableCode} {@code +GeneratePIC} compilation, false 651 * otherwise. 652 */ 653 public boolean isImmutablePIC() { 654 return isImmutablePIC; 655 } 656 657 /** 658 * @return the entryBCI 659 */ 660 public int getEntryBCI() { 661 return entryBCI; 662 } 663 664 /** 665 * @param entryBCI the entryBCI to set 666 */ 667 public void setEntryBCI(int entryBCI) { 668 this.entryBCI = entryBCI; 669 } 670 671 /** 672 * Sets the assumptions made during compilation. 673 */ 674 public void setAssumptions(Assumption[] assumptions) { 675 this.assumptions = assumptions; 676 } 677 678 /** 679 * Gets the assumptions made during compilation. 680 */ 681 public Assumption[] getAssumptions() { 682 return assumptions; 683 } 684 685 /** 686 * Sets the methods whose bytecodes were used as input to the compilation. 687 * 688 * @param rootMethod the root method of the compilation 689 * @param inlinedMethods the methods inlined during compilation 690 */ 691 public void setMethods(ResolvedJavaMethod rootMethod, Collection<ResolvedJavaMethod> inlinedMethods) { 692 assert rootMethod != null; 693 assert inlinedMethods != null; 694 if (inlinedMethods.contains(rootMethod)) { 695 methods = inlinedMethods.toArray(new ResolvedJavaMethod[inlinedMethods.size()]); 696 for (int i = 0; i < methods.length; i++) { 697 if (methods[i].equals(rootMethod)) { 698 if (i != 0) { 699 ResolvedJavaMethod tmp = methods[0]; 700 methods[0] = methods[i]; 701 methods[i] = tmp; 702 } 703 break; 704 } 705 } 706 } else { 707 methods = new ResolvedJavaMethod[1 + inlinedMethods.size()]; 708 methods[0] = rootMethod; 709 int i = 1; 710 for (ResolvedJavaMethod m : inlinedMethods) { 711 methods[i++] = m; 712 } 713 } 714 } 715 716 /** 717 * Gets the methods whose bytecodes were used as input to the compilation. 718 * 719 * @return {@code null} if the compilation did not record method dependencies otherwise the 720 * methods whose bytecodes were used as input to the compilation with the first element 721 * being the root method of the compilation 722 */ 723 public ResolvedJavaMethod[] getMethods() { 724 return methods; 725 } 726 727 public void setBytecodeSize(int bytecodeSize) { 728 this.bytecodeSize = bytecodeSize; 729 } 730 731 public int getBytecodeSize() { 732 return bytecodeSize; 733 } 734 735 public DataSection getDataSection() { 736 return dataSection; 737 } 738 739 /** 740 * The total frame size of the method in bytes. This includes the return address pushed onto the 741 * stack, if any. 742 * 743 * @return the frame size 744 */ 745 public int getTotalFrameSize() { 746 assert totalFrameSize != -1 : "frame size not yet initialized!"; 747 return totalFrameSize; 748 } 749 750 /** 751 * Sets the total frame size in bytes. This includes the return address pushed onto the stack, 752 * if any. 753 * 754 * @param size the size of the frame in bytes 755 */ 756 public void setTotalFrameSize(int size) { 757 totalFrameSize = size; 758 } 759 760 /** 761 * Sets the machine that has been generated by the compiler. 762 * 763 * @param code the machine code generated 764 * @param size the size of the machine code 765 */ 766 public void setTargetCode(byte[] code, int size) { 767 targetCode = code; 768 targetCodeSize = size; 769 } 770 771 /** 772 * Records a data patch in the code section. The data patch can refer to something in the 773 * {@link DataSectionReference data section} or directly to an {@link ConstantReference inlined 774 * constant}. 775 * 776 * @param codePos The position in the code that needs to be patched. 777 * @param ref The reference that should be inserted in the code. 778 */ 779 public void recordDataPatch(int codePos, Reference ref) { 780 assert codePos >= 0 && ref != null; 781 dataPatches.add(new DataPatch(codePos, ref)); 782 } 783 784 /** 785 * Records a data patch in the code section. The data patch can refer to something in the 786 * {@link DataSectionReference data section} or directly to an {@link ConstantReference inlined 787 * constant}. 788 * 789 * @param codePos The position in the code that needs to be patched. 790 * @param ref The reference that should be inserted in the code. 791 * @param note The note attached to data patch for use by post-processing tools 792 */ 793 public void recordDataPatchWithNote(int codePos, Reference ref, Object note) { 794 assert codePos >= 0 && ref != null; 795 dataPatches.add(new DataPatch(codePos, ref, note)); 796 } 797 798 /** 799 * Records metaspace access. 800 */ 801 public void recordMetaspaceAccess(Object reference, int instructionSize, MetaSpaceAccessType type, int codePos, DebugInfo debugInfo) { 802 final MetaSpaceAccess metaspace = new MetaSpaceAccess(reference, instructionSize, type, codePos, debugInfo); 803 addInfopoint(metaspace); 804 } 805 806 /** 807 * Records a call in the code array. 808 * 809 * @param codePos the position of the call in the code array 810 * @param size the size of the call instruction 811 * @param target the being called 812 * @param debugInfo the debug info for the call 813 * @param direct specifies if this is a {@linkplain Call#direct direct} call 814 */ 815 public void recordCall(int codePos, int size, InvokeTarget target, DebugInfo debugInfo, boolean direct) { 816 final Call call = new Call(target, codePos, size, direct, debugInfo); 817 addInfopoint(call); 818 } 819 820 /** 821 * Records an exception handler for this method. 822 * 823 * @param codePos the position in the code that is covered by the handler 824 * @param handlerPos the position of the handler 825 */ 826 public void recordExceptionHandler(int codePos, int handlerPos) { 827 assert validateExceptionHandlerAdd(codePos, handlerPos) : String.format("Duplicate exception handler for pc 0x%x handlerPos 0x%x", codePos, handlerPos); 828 exceptionHandlers.add(new ExceptionHandler(codePos, handlerPos)); 829 } 830 831 /** 832 * Validate if the exception handler for codePos already exists and handlerPos is different. 833 * 834 * @param codePos 835 * @param handlerPos 836 * @return true if the validation is successful 837 */ 838 private boolean validateExceptionHandlerAdd(int codePos, int handlerPos) { 839 ExceptionHandler exHandler = getExceptionHandlerForCodePos(codePos); 840 return exHandler == null || exHandler.handlerPos == handlerPos; 841 } 842 843 /** 844 * Returns the first ExceptionHandler which matches codePos. 845 * 846 * @param codePos position to search for 847 * @return first matching ExceptionHandler 848 */ 849 private ExceptionHandler getExceptionHandlerForCodePos(int codePos) { 850 for (ExceptionHandler h : exceptionHandlers) { 851 if (h.pcOffset == codePos) { 852 return h; 853 } 854 } 855 return null; 856 } 857 858 /** 859 * Records an infopoint in the code array. 860 * 861 * @param codePos the position of the infopoint in the code array 862 * @param debugInfo the debug info for the infopoint 863 */ 864 public void recordInfopoint(int codePos, DebugInfo debugInfo, InfopointReason reason) { 865 addInfopoint(new Infopoint(codePos, debugInfo, reason)); 866 } 867 868 /** 869 * Records a custom infopoint in the code section. 870 * 871 * Compiler implementations can use this method to record non-standard infopoints, which are not 872 * handled by the dedicated methods like {@link #recordCall}. 873 * 874 * @param infopoint the infopoint to record, usually a derived class from {@link Infopoint} 875 */ 876 public void addInfopoint(Infopoint infopoint) { 877 // The infopoints list must always be sorted 878 if (!infopoints.isEmpty()) { 879 Infopoint previousInfopoint = infopoints.get(infopoints.size() - 1); 880 if (previousInfopoint.pcOffset > infopoint.pcOffset) { 881 // This re-sorting should be very rare 882 Collections.sort(infopoints); 883 previousInfopoint = infopoints.get(infopoints.size() - 1); 884 } 885 if (previousInfopoint.pcOffset == infopoint.pcOffset) { 886 if (infopoint.reason.canBeOmitted()) { 887 return; 888 } 889 if (previousInfopoint.reason.canBeOmitted()) { 890 Infopoint removed = infopoints.remove(infopoints.size() - 1); 891 assert removed == previousInfopoint; 892 } else { 893 throw new RuntimeException("Infopoints that can not be omited should have distinct PCs"); 894 } 895 } 896 } 897 infopoints.add(infopoint); 898 } 899 900 /** 901 * Records an instruction mark within this method. 902 * 903 * @param codePos the position in the code that is covered by the handler 904 * @param markId the identifier for this mark 905 */ 906 public Mark recordMark(int codePos, Object markId) { 907 Mark mark = new Mark(codePos, markId); 908 marks.add(mark); 909 return mark; 910 } 911 912 /** 913 * Offset in bytes for the custom stack area (relative to sp). 914 * 915 * @return the offset in bytes 916 */ 917 public int getCustomStackAreaOffset() { 918 return customStackAreaOffset; 919 } 920 921 /** 922 * @see #getCustomStackAreaOffset() 923 * @param offset 924 */ 925 public void setCustomStackAreaOffset(int offset) { 926 customStackAreaOffset = offset; 927 } 928 929 /** 930 * @return the machine code generated for this method 931 */ 932 public byte[] getTargetCode() { 933 return targetCode; 934 } 935 936 /** 937 * @return the size of the machine code generated for this method 938 */ 939 public int getTargetCodeSize() { 940 return targetCodeSize; 941 } 942 943 /** 944 * @return the code annotations or {@code null} if there are none 945 */ 946 public List<CodeAnnotation> getAnnotations() { 947 if (annotations == null) { 948 return Collections.emptyList(); 949 } 950 return annotations; 951 } 952 953 public void addAnnotation(CodeAnnotation annotation) { 954 assert annotation != null; 955 if (annotations == null) { 956 annotations = new ArrayList<>(); 957 } 958 annotations.add(annotation); 959 } 960 961 private static void appendDebugInfo(StringBuilder sb, DebugInfo info) { 962 if (info != null) { 963 ReferenceMap refMap = info.getReferenceMap(); 964 if (refMap != null) { 965 sb.append(refMap.toString()); 966 sb.append(']'); 967 } 968 RegisterSaveLayout calleeSaveInfo = info.getCalleeSaveInfo(); 969 if (calleeSaveInfo != null) { 970 sb.append(" callee-save-info["); 971 String sep = ""; 972 for (Map.Entry<Register, Integer> e : calleeSaveInfo.registersToSlots(true).entrySet()) { 973 sb.append(sep).append(e.getKey()).append("->").append(e.getValue()); 974 sep = ", "; 975 } 976 sb.append(']'); 977 } 978 BytecodePosition codePos = info.getBytecodePosition(); 979 if (codePos != null) { 980 MetaUtil.appendLocation(sb.append(" "), codePos.getMethod(), codePos.getBCI()); 981 if (info.hasFrame()) { 982 sb.append(" #locals=").append(info.frame().numLocals).append(" #expr=").append(info.frame().numStack); 983 if (info.frame().numLocks > 0) { 984 sb.append(" #locks=").append(info.frame().numLocks); 985 } 986 } 987 } 988 } 989 } 990 991 /** 992 * @return the list of infopoints, sorted by {@link Site#pcOffset} 993 */ 994 public List<Infopoint> getInfopoints() { 995 if (infopoints.isEmpty()) { 996 return emptyList(); 997 } 998 return unmodifiableList(infopoints); 999 } 1000 1001 /** 1002 * @return the list of data references 1003 */ 1004 public List<DataPatch> getDataPatches() { 1005 if (dataPatches.isEmpty()) { 1006 return emptyList(); 1007 } 1008 return unmodifiableList(dataPatches); 1009 } 1010 1011 /** 1012 * @return the list of exception handlers 1013 */ 1014 public List<ExceptionHandler> getExceptionHandlers() { 1015 if (exceptionHandlers.isEmpty()) { 1016 return emptyList(); 1017 } 1018 return unmodifiableList(exceptionHandlers); 1019 } 1020 1021 /** 1022 * @return the list of marks 1023 */ 1024 public List<Mark> getMarks() { 1025 if (marks.isEmpty()) { 1026 return emptyList(); 1027 } 1028 return unmodifiableList(marks); 1029 } 1030 1031 public String getName() { 1032 return name; 1033 } 1034 1035 public void setHasUnsafeAccess(boolean hasUnsafeAccess) { 1036 this.hasUnsafeAccess = hasUnsafeAccess; 1037 } 1038 1039 public boolean hasUnsafeAccess() { 1040 return hasUnsafeAccess; 1041 } 1042 1043 public void reset() { 1044 hasUnsafeAccess = false; 1045 infopoints.clear(); 1046 dataPatches.clear(); 1047 exceptionHandlers.clear(); 1048 marks.clear(); 1049 dataSection.clear(); 1050 if (annotations != null) { 1051 annotations.clear(); 1052 } 1053 } 1054 }