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