1 /*
   2  * Copyright (c) 2009, 2019, 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 
  24 
  25 package org.graalvm.compiler.code;
  26 
  27 import static java.util.Collections.emptyList;
  28 import static java.util.Collections.unmodifiableList;
  29 import static jdk.vm.ci.meta.MetaUtil.identityHashCodeString;
  30 
  31 import java.util.ArrayList;
  32 import java.util.Arrays;
  33 import java.util.Collection;
  34 import java.util.Collections;
  35 import java.util.List;
  36 import java.util.Objects;
  37 
  38 import jdk.internal.vm.compiler.collections.EconomicSet;
  39 import org.graalvm.compiler.core.common.CompilationIdentifier;
  40 import org.graalvm.compiler.graph.NodeSourcePosition;
  41 
  42 import jdk.vm.ci.code.DebugInfo;
  43 import jdk.vm.ci.code.StackSlot;
  44 import jdk.vm.ci.code.site.Call;
  45 import jdk.vm.ci.code.site.ConstantReference;
  46 import jdk.vm.ci.code.site.DataPatch;
  47 import jdk.vm.ci.code.site.DataSectionReference;
  48 import jdk.vm.ci.code.site.ExceptionHandler;
  49 import jdk.vm.ci.code.site.Infopoint;
  50 import jdk.vm.ci.code.site.InfopointReason;
  51 import jdk.vm.ci.code.site.Mark;
  52 import jdk.vm.ci.code.site.Reference;
  53 import jdk.vm.ci.code.site.Site;
  54 import jdk.vm.ci.meta.Assumptions.Assumption;
  55 import jdk.vm.ci.meta.InvokeTarget;
  56 import jdk.vm.ci.meta.ResolvedJavaField;
  57 import jdk.vm.ci.meta.ResolvedJavaMethod;
  58 import jdk.vm.ci.meta.SpeculationLog;
  59 
  60 /**
  61  * Represents the output from compiling a method, including the compiled machine code, associated
  62  * data and references, relocation information, deoptimization information, etc.
  63  */
  64 public class CompilationResult {
  65 
  66     /**
  67      * Provides extra information about instructions or data at specific positions in
  68      * {@link CompilationResult#getTargetCode()}. This is optional information that can be used to
  69      * enhance a disassembly of the code.
  70      */
  71     public abstract static class CodeAnnotation {
  72 
  73         public final int position;
  74 
  75         public CodeAnnotation(int position) {
  76             this.position = position;
  77         }
  78 
  79         @Override
  80         public final int hashCode() {
  81             throw new UnsupportedOperationException("hashCode");
  82         }
  83 
  84         @Override
  85         public String toString() {
  86             return identityHashCodeString(this);
  87         }
  88 
  89         @Override
  90         public abstract boolean equals(Object obj);
  91     }
  92 
  93     /**
  94      * A string comment about one or more instructions at a specific position in the code.
  95      */
  96     public static final class CodeComment extends CodeAnnotation {
  97 
  98         public final String value;
  99 
 100         public CodeComment(int position, String comment) {
 101             super(position);
 102             this.value = comment;
 103         }
 104 
 105         @Override
 106         public boolean equals(Object obj) {
 107             if (this == obj) {
 108                 return true;
 109             }
 110             if (obj instanceof CodeComment) {
 111                 CodeComment that = (CodeComment) obj;
 112                 if (this.position == that.position && this.value.equals(that.value)) {
 113                     return true;
 114                 }
 115             }
 116             return false;
 117         }
 118 
 119         @Override
 120         public String toString() {
 121             return getClass().getSimpleName() + "@" + position + ": " + value;
 122         }
 123     }
 124 
 125     /**
 126      * Describes a table of signed offsets embedded in the code. The offsets are relative to the
 127      * starting address of the table. This type of table maybe generated when translating a
 128      * multi-way branch based on a key value from a dense value set (e.g. the {@code tableswitch}
 129      * JVM instruction).
 130      *
 131      * The table is indexed by the contiguous range of integers from {@link #low} to {@link #high}
 132      * inclusive.
 133      */
 134     public static final class JumpTable extends CodeAnnotation {
 135 
 136         /**
 137          * The low value in the key range (inclusive).
 138          */
 139         public final int low;
 140 
 141         /**
 142          * The high value in the key range (inclusive).
 143          */
 144         public final int high;
 145 
 146         /**
 147          * The size (in bytes) of each table entry.
 148          */
 149         public final int entrySize;
 150 
 151         public JumpTable(int position, int low, int high, int entrySize) {
 152             super(position);
 153             this.low = low;
 154             this.high = high;
 155             this.entrySize = entrySize;
 156         }
 157 
 158         @Override
 159         public boolean equals(Object obj) {
 160             if (this == obj) {
 161                 return true;
 162             }
 163             if (obj instanceof JumpTable) {
 164                 JumpTable that = (JumpTable) obj;
 165                 if (this.position == that.position && this.entrySize == that.entrySize && this.low == that.low && this.high == that.high) {
 166                     return true;
 167                 }
 168             }
 169             return false;
 170         }
 171 
 172         @Override
 173         public String toString() {
 174             return getClass().getSimpleName() + "@" + position + ": [" + low + " .. " + high + "]";
 175         }
 176     }
 177 
 178     private boolean closed;
 179 
 180     private int entryBCI = -1;
 181 
 182     private final DataSection dataSection = new DataSection();
 183 
 184     private final List<Infopoint> infopoints = new ArrayList<>();
 185     private final List<SourceMapping> sourceMapping = new ArrayList<>();
 186     private final List<DataPatch> dataPatches = new ArrayList<>();
 187     private final List<ExceptionHandler> exceptionHandlers = new ArrayList<>();
 188     private final List<Mark> marks = new ArrayList<>();
 189 
 190     private int totalFrameSize = -1;
 191     private int maxInterpreterFrameSize = -1;
 192 
 193     private StackSlot customStackArea = null;
 194 
 195     /**
 196      * A customized name that is unrelated to {@link #compilationId}. Can be null if
 197      * {@link #compilationId} fully describes the compilation.
 198      */
 199     private final String name;
 200 
 201     private final CompilationIdentifier compilationId;
 202 
 203     /**
 204      * The buffer containing the emitted machine code.
 205      */
 206     private byte[] targetCode;
 207 
 208     /**
 209      * The leading number of bytes in {@link #targetCode} containing the emitted machine code.
 210      */
 211     private int targetCodeSize;
 212 
 213     private ArrayList<CodeAnnotation> annotations;
 214 
 215     private Assumption[] assumptions;
 216 
 217     /**
 218      * The list of the methods whose bytecodes were used as input to the compilation. If
 219      * {@code null}, then the compilation did not record method dependencies. Otherwise, the first
 220      * element of this array is the root method of the compilation.
 221      */
 222     private ResolvedJavaMethod[] methods;
 223 
 224     /**
 225      * The {@link SpeculationLog} log used during compilation.
 226      */
 227     private SpeculationLog speculationLog;
 228 
 229     /**
 230      * The list of fields that were accessed from the bytecodes.
 231      */
 232     private ResolvedJavaField[] fields;
 233 
 234     private int bytecodeSize;
 235 
 236     private boolean hasUnsafeAccess;
 237 
 238     private boolean isImmutablePIC;
 239 
 240     public CompilationResult(CompilationIdentifier compilationId) {
 241         this(compilationId, null, false);
 242     }
 243 
 244     public CompilationResult(CompilationIdentifier compilationId, String name) {
 245         this(compilationId, name, false);
 246     }
 247 
 248     public CompilationResult(CompilationIdentifier compilationId, boolean isImmutablePIC) {
 249         this(compilationId, null, isImmutablePIC);
 250     }
 251 
 252     public CompilationResult(CompilationIdentifier compilationId, String name, boolean isImmutablePIC) {
 253         this.compilationId = compilationId;
 254         this.name = name;
 255         this.isImmutablePIC = isImmutablePIC;
 256     }
 257 
 258     public CompilationResult(String name) {
 259         this(null, name);
 260     }
 261 
 262     @Override
 263     public int hashCode() {
 264         // CompilationResult instances should not be used as hash map keys
 265         throw new UnsupportedOperationException("hashCode");
 266     }
 267 
 268     @Override
 269     public String toString() {
 270         if (methods != null) {
 271             return getClass().getName() + "[" + methods[0].format("%H.%n(%p)%r") + "]";
 272         }
 273         return identityHashCodeString(this);
 274     }
 275 
 276     @Override
 277     public boolean equals(Object obj) {
 278         if (this == obj) {
 279             return true;
 280         }
 281         if (obj != null && obj.getClass() == getClass()) {
 282             CompilationResult that = (CompilationResult) obj;
 283             // @formatter:off
 284             if (this.entryBCI == that.entryBCI &&
 285                 Objects.equals(this.customStackArea, that.customStackArea) &&
 286                 this.totalFrameSize == that.totalFrameSize &&
 287                 this.targetCodeSize == that.targetCodeSize &&
 288                 Objects.equals(this.name, that.name) &&
 289                 Objects.equals(this.compilationId, that.compilationId) &&
 290                 Objects.equals(this.annotations, that.annotations) &&
 291                 Objects.equals(this.dataSection, that.dataSection) &&
 292                 Objects.equals(this.exceptionHandlers, that.exceptionHandlers) &&
 293                 Objects.equals(this.dataPatches, that.dataPatches) &&
 294                 Objects.equals(this.infopoints, that.infopoints) &&
 295                 Objects.equals(this.marks,  that.marks) &&
 296                 Arrays.equals(this.assumptions, that.assumptions) &&
 297                 Arrays.equals(targetCode, that.targetCode)) {
 298                 return true;
 299             }
 300             // @formatter:on
 301         }
 302         return false;
 303     }
 304 
 305     /**
 306      * @return the entryBCI
 307      */
 308     public int getEntryBCI() {
 309         return entryBCI;
 310     }
 311 
 312     /**
 313      * @param entryBCI the entryBCI to set
 314      */
 315     public void setEntryBCI(int entryBCI) {
 316         checkOpen();
 317         this.entryBCI = entryBCI;
 318     }
 319 
 320     /**
 321      * Sets the assumptions made during compilation.
 322      */
 323     public void setAssumptions(Assumption[] assumptions) {
 324         this.assumptions = assumptions;
 325     }
 326 
 327     /**
 328      * Gets the assumptions made during compilation.
 329      *
 330      * The caller must not modify the contents of the returned array.
 331      */
 332     public Assumption[] getAssumptions() {
 333         return assumptions;
 334     }
 335 
 336     /**
 337      * Sets the methods whose bytecodes were used as input to the compilation.
 338      *
 339      * @param rootMethod the root method of the compilation
 340      * @param inlinedMethods the methods inlined during compilation
 341      */
 342     public void setMethods(ResolvedJavaMethod rootMethod, Collection<ResolvedJavaMethod> inlinedMethods) {
 343         checkOpen();
 344         assert rootMethod != null;
 345         assert inlinedMethods != null;
 346         if (inlinedMethods.contains(rootMethod)) {
 347             methods = inlinedMethods.toArray(new ResolvedJavaMethod[inlinedMethods.size()]);
 348             for (int i = 0; i < methods.length; i++) {
 349                 if (methods[i].equals(rootMethod)) {
 350                     if (i != 0) {
 351                         ResolvedJavaMethod tmp = methods[0];
 352                         methods[0] = methods[i];
 353                         methods[i] = tmp;
 354                     }
 355                     break;
 356                 }
 357             }
 358         } else {
 359             methods = new ResolvedJavaMethod[1 + inlinedMethods.size()];
 360             methods[0] = rootMethod;
 361             int i = 1;
 362             for (ResolvedJavaMethod m : inlinedMethods) {
 363                 methods[i++] = m;
 364             }
 365         }
 366     }
 367 
 368     /**
 369      * Gets the methods whose bytecodes were used as input to the compilation.
 370      *
 371      * The caller must not modify the contents of the returned array.
 372      *
 373      * @return {@code null} if the compilation did not record method dependencies otherwise the
 374      *         methods whose bytecodes were used as input to the compilation with the first element
 375      *         being the root method of the compilation
 376      */
 377     public ResolvedJavaMethod[] getMethods() {
 378         return methods;
 379     }
 380 
 381     /**
 382      * Sets the {@link SpeculationLog} log used during compilation.
 383      */
 384     public void setSpeculationLog(SpeculationLog speculationLog) {
 385         checkOpen();
 386         this.speculationLog = speculationLog;
 387     }
 388 
 389     /**
 390      * Gets the {@link SpeculationLog} log, if any, used during compilation.
 391      */
 392     public SpeculationLog getSpeculationLog() {
 393         return speculationLog;
 394     }
 395 
 396     /**
 397      * Sets the fields that were referenced from the bytecodes that were used as input to the
 398      * compilation.
 399      *
 400      * @param accessedFields the collected set of fields accessed during compilation
 401      */
 402     public void setFields(EconomicSet<ResolvedJavaField> accessedFields) {
 403         if (accessedFields != null) {
 404             fields = accessedFields.toArray(new ResolvedJavaField[accessedFields.size()]);
 405         }
 406     }
 407 
 408     /**
 409      * Gets the fields that were referenced from bytecodes that were used as input to the
 410      * compilation.
 411      *
 412      * The caller must not modify the contents of the returned array.
 413      *
 414      * @return {@code null} if the compilation did not record fields dependencies otherwise the
 415      *         fields that were accessed from bytecodes were used as input to the compilation.
 416      */
 417     public ResolvedJavaField[] getFields() {
 418         return fields;
 419     }
 420 
 421     public void setBytecodeSize(int bytecodeSize) {
 422         checkOpen();
 423         this.bytecodeSize = bytecodeSize;
 424     }
 425 
 426     public int getBytecodeSize() {
 427         return bytecodeSize;
 428     }
 429 
 430     public DataSection getDataSection() {
 431         return dataSection;
 432     }
 433 
 434     /**
 435      * The total frame size of the method in bytes. This includes the return address pushed onto the
 436      * stack, if any.
 437      *
 438      * @return the frame size
 439      */
 440     public int getTotalFrameSize() {
 441         assert totalFrameSize != -1 : "frame size not yet initialized!";
 442         return totalFrameSize;
 443     }
 444 
 445     /**
 446      * Sets the total frame size in bytes. This includes the return address pushed onto the stack,
 447      * if any.
 448      *
 449      * @param size the size of the frame in bytes
 450      */
 451     public void setTotalFrameSize(int size) {
 452         checkOpen();
 453         totalFrameSize = size;
 454     }
 455 
 456     public int getMaxInterpreterFrameSize() {
 457         return maxInterpreterFrameSize;
 458     }
 459 
 460     public void setMaxInterpreterFrameSize(int maxInterpreterFrameSize) {
 461         checkOpen();
 462         this.maxInterpreterFrameSize = maxInterpreterFrameSize;
 463     }
 464 
 465     public boolean isImmutablePIC() {
 466         return this.isImmutablePIC;
 467     }
 468 
 469     /**
 470      * Sets the machine that has been generated by the compiler.
 471      *
 472      * @param code the machine code generated
 473      * @param size the size of the machine code
 474      */
 475     public void setTargetCode(byte[] code, int size) {
 476         checkOpen();
 477         targetCode = code;
 478         targetCodeSize = size;
 479     }
 480 
 481     /**
 482      * Records a data patch in the code section. The data patch can refer to something in the
 483      * {@link DataSectionReference data section} or directly to an {@link ConstantReference inlined
 484      * constant}.
 485      *
 486      * @param codePos the position in the code that needs to be patched
 487      * @param ref the reference that should be inserted in the code
 488      */
 489     public void recordDataPatch(int codePos, Reference ref) {
 490         checkOpen();
 491         assert codePos >= 0 && ref != null;
 492         dataPatches.add(new DataPatch(codePos, ref));
 493     }
 494 
 495     /**
 496      * Records a data patch in the code section. The data patch can refer to something in the
 497      * {@link DataSectionReference data section} or directly to an {@link ConstantReference inlined
 498      * constant}.
 499      *
 500      * @param codePos the position in the code that needs to be patched
 501      * @param ref the reference that should be inserted in the code
 502      * @param note a note attached to data patch for use by post-processing tools
 503      */
 504     public void recordDataPatchWithNote(int codePos, Reference ref, Object note) {
 505         assert codePos >= 0 && ref != null;
 506         dataPatches.add(new DataPatch(codePos, ref, note));
 507     }
 508 
 509     /**
 510      * Records a call in the code array.
 511      *
 512      * @param codePos the position of the call in the code array
 513      * @param size the size of the call instruction
 514      * @param target the being called
 515      * @param debugInfo the debug info for the call
 516      * @param direct specifies if this is a {@linkplain Call#direct direct} call
 517      */
 518     public void recordCall(int codePos, int size, InvokeTarget target, DebugInfo debugInfo, boolean direct) {
 519         checkOpen();
 520         final Call call = new Call(target, codePos, size, direct, debugInfo);
 521         addInfopoint(call);
 522     }
 523 
 524     /**
 525      * Records an exception handler for this method.
 526      *
 527      * @param codePos the position in the code that is covered by the handler
 528      * @param handlerPos the position of the handler
 529      */
 530     public void recordExceptionHandler(int codePos, int handlerPos) {
 531         checkOpen();
 532         assert validateExceptionHandlerAdd(codePos, handlerPos) : String.format("Duplicate exception handler for pc 0x%x handlerPos 0x%x", codePos, handlerPos);
 533         exceptionHandlers.add(new ExceptionHandler(codePos, handlerPos));
 534     }
 535 
 536     /**
 537      * Validate if the exception handler for codePos already exists and handlerPos is different.
 538      *
 539      * @param codePos
 540      * @param handlerPos
 541      * @return true if the validation is successful
 542      */
 543     private boolean validateExceptionHandlerAdd(int codePos, int handlerPos) {
 544         ExceptionHandler exHandler = getExceptionHandlerForCodePos(codePos);
 545         return exHandler == null || exHandler.handlerPos == handlerPos;
 546     }
 547 
 548     /**
 549      * Returns the first ExceptionHandler which matches codePos.
 550      *
 551      * @param codePos position to search for
 552      * @return first matching ExceptionHandler
 553      */
 554     private ExceptionHandler getExceptionHandlerForCodePos(int codePos) {
 555         for (ExceptionHandler h : exceptionHandlers) {
 556             if (h.pcOffset == codePos) {
 557                 return h;
 558             }
 559         }
 560         return null;
 561     }
 562 
 563     /**
 564      * Records an infopoint in the code array.
 565      *
 566      * @param codePos the position of the infopoint in the code array
 567      * @param debugInfo the debug info for the infopoint
 568      */
 569     public void recordInfopoint(int codePos, DebugInfo debugInfo, InfopointReason reason) {
 570         addInfopoint(new Infopoint(codePos, debugInfo, reason));
 571     }
 572 
 573     /**
 574      * Records a custom infopoint in the code section.
 575      *
 576      * Compiler implementations can use this method to record non-standard infopoints, which are not
 577      * handled by dedicated methods like {@link #recordCall}.
 578      *
 579      * @param infopoint the infopoint to record, usually a derived class from {@link Infopoint}
 580      */
 581     public void addInfopoint(Infopoint infopoint) {
 582         checkOpen();
 583         infopoints.add(infopoint);
 584     }
 585 
 586     public void recordSourceMapping(int startOffset, int endOffset, NodeSourcePosition sourcePosition) {
 587         checkOpen();
 588         sourceMapping.add(new SourceMapping(startOffset, endOffset, sourcePosition));
 589     }
 590 
 591     /**
 592      * Records an instruction mark within this method.
 593      *
 594      * @param codePos the position in the code that is covered by the handler
 595      * @param markId the identifier for this mark
 596      */
 597     public Mark recordMark(int codePos, Object markId) {
 598         checkOpen();
 599         Mark mark = new Mark(codePos, markId);
 600         marks.add(mark);
 601         return mark;
 602     }
 603 
 604     /**
 605      * Start of the custom stack area.
 606      *
 607      * @return the first stack slot of the custom stack area
 608      */
 609     public StackSlot getCustomStackArea() {
 610         return customStackArea;
 611     }
 612 
 613     /**
 614      * @see #getCustomStackArea()
 615      * @param slot
 616      */
 617     public void setCustomStackAreaOffset(StackSlot slot) {
 618         checkOpen();
 619         customStackArea = slot;
 620     }
 621 
 622     /**
 623      * @return the machine code generated for this method
 624      */
 625     public byte[] getTargetCode() {
 626         return targetCode;
 627     }
 628 
 629     /**
 630      * @return the size of the machine code generated for this method
 631      */
 632     public int getTargetCodeSize() {
 633         return targetCodeSize;
 634     }
 635 
 636     /**
 637      * @return the code annotations or {@code null} if there are none
 638      */
 639     public List<CodeAnnotation> getCodeAnnotations() {
 640         if (annotations == null) {
 641             return Collections.emptyList();
 642         }
 643         return annotations;
 644     }
 645 
 646     public void addAnnotation(CodeAnnotation annotation) {
 647         checkOpen();
 648         assert annotation != null;
 649         if (annotations == null) {
 650             annotations = new ArrayList<>();
 651         }
 652         annotations.add(annotation);
 653     }
 654 
 655     /**
 656      * @return the list of infopoints, sorted by {@link Site#pcOffset}
 657      */
 658     public List<Infopoint> getInfopoints() {
 659         if (infopoints.isEmpty()) {
 660             return emptyList();
 661         }
 662         return unmodifiableList(infopoints);
 663     }
 664 
 665     /**
 666      * @return the list of data references
 667      */
 668     public List<DataPatch> getDataPatches() {
 669         if (dataPatches.isEmpty()) {
 670             return emptyList();
 671         }
 672         return unmodifiableList(dataPatches);
 673     }
 674 
 675     /**
 676      * @return the list of exception handlers
 677      */
 678     public List<ExceptionHandler> getExceptionHandlers() {
 679         if (exceptionHandlers.isEmpty()) {
 680             return emptyList();
 681         }
 682         return unmodifiableList(exceptionHandlers);
 683     }
 684 
 685     /**
 686      * @return the list of marks
 687      */
 688     public List<Mark> getMarks() {
 689         if (marks.isEmpty()) {
 690             return emptyList();
 691         }
 692         return unmodifiableList(marks);
 693     }
 694 
 695     /**
 696      * @return the list of {@link SourceMapping}s
 697      */
 698     public List<SourceMapping> getSourceMappings() {
 699         if (sourceMapping.isEmpty()) {
 700             return emptyList();
 701         }
 702         return unmodifiableList(sourceMapping);
 703     }
 704 
 705     /**
 706      * Gets the name for this compilation result. This will only be non-null when it provides a
 707      * value unrelated to {@link #getCompilationId()}.
 708      */
 709     public String getName() {
 710         return name;
 711     }
 712 
 713     public CompilationIdentifier getCompilationId() {
 714         return compilationId;
 715     }
 716 
 717     public void setHasUnsafeAccess(boolean hasUnsafeAccess) {
 718         checkOpen();
 719         this.hasUnsafeAccess = hasUnsafeAccess;
 720     }
 721 
 722     public boolean hasUnsafeAccess() {
 723         return hasUnsafeAccess;
 724     }
 725 
 726     /**
 727      * Clears the information in this object pertaining to generating code. That is, the
 728      * {@linkplain #getMarks() marks}, {@linkplain #getInfopoints() infopoints},
 729      * {@linkplain #getExceptionHandlers() exception handlers}, {@linkplain #getDataPatches() data
 730      * patches} and {@linkplain #getCodeAnnotations() annotations} recorded in this object are
 731      * cleared.
 732      */
 733     public void resetForEmittingCode() {
 734         checkOpen();
 735         infopoints.clear();
 736         sourceMapping.clear();
 737         dataPatches.clear();
 738         exceptionHandlers.clear();
 739         marks.clear();
 740         dataSection.clear();
 741         if (annotations != null) {
 742             annotations.clear();
 743         }
 744     }
 745 
 746     public void clearInfopoints() {
 747         infopoints.clear();
 748     }
 749 
 750     public void clearExceptionHandlers() {
 751         exceptionHandlers.clear();
 752     }
 753 
 754     private void checkOpen() {
 755         if (closed) {
 756             throw new IllegalStateException();
 757         }
 758     }
 759 
 760     /**
 761      * Closes this compilation result to future updates.
 762      */
 763     public void close() {
 764         if (closed) {
 765             throw new IllegalStateException("Cannot re-close compilation result " + this);
 766         }
 767         dataSection.close();
 768         closed = true;
 769     }
 770 }