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 }