1 /*
   2  * Copyright (c) 2013, 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.lir.asm;
  26 
  27 import static jdk.vm.ci.code.ValueUtil.asStackSlot;
  28 import static jdk.vm.ci.code.ValueUtil.isStackSlot;
  29 import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant;
  30 import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant;
  31 
  32 import java.util.ArrayList;
  33 import java.util.Arrays;
  34 import java.util.List;
  35 import java.util.function.Consumer;
  36 
  37 import jdk.internal.vm.compiler.collections.EconomicMap;
  38 import jdk.internal.vm.compiler.collections.Equivalence;
  39 import org.graalvm.compiler.asm.AbstractAddress;
  40 import org.graalvm.compiler.asm.Assembler;
  41 import org.graalvm.compiler.asm.Label;
  42 import org.graalvm.compiler.code.CompilationResult;
  43 import org.graalvm.compiler.code.CompilationResult.CodeAnnotation;
  44 import org.graalvm.compiler.code.DataSection.Data;
  45 import org.graalvm.compiler.code.DataSection.RawData;
  46 import org.graalvm.compiler.core.common.NumUtil;
  47 import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
  48 import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
  49 import org.graalvm.compiler.core.common.type.DataPointerConstant;
  50 import org.graalvm.compiler.debug.DebugContext;
  51 import org.graalvm.compiler.debug.GraalError;
  52 import org.graalvm.compiler.graph.NodeSourcePosition;
  53 import org.graalvm.compiler.lir.LIR;
  54 import org.graalvm.compiler.lir.LIRFrameState;
  55 import org.graalvm.compiler.lir.LIRInstruction;
  56 import org.graalvm.compiler.lir.LabelRef;
  57 import org.graalvm.compiler.lir.StandardOp.LabelHoldingOp;
  58 import org.graalvm.compiler.lir.framemap.FrameMap;
  59 import org.graalvm.compiler.options.Option;
  60 import org.graalvm.compiler.options.OptionKey;
  61 import org.graalvm.compiler.options.OptionType;
  62 import org.graalvm.compiler.options.OptionValues;
  63 
  64 import jdk.vm.ci.code.BailoutException;
  65 import jdk.vm.ci.code.CodeCacheProvider;
  66 import jdk.vm.ci.code.DebugInfo;
  67 import jdk.vm.ci.code.Register;
  68 import jdk.vm.ci.code.StackSlot;
  69 import jdk.vm.ci.code.TargetDescription;
  70 import jdk.vm.ci.code.site.ConstantReference;
  71 import jdk.vm.ci.code.site.DataSectionReference;
  72 import jdk.vm.ci.code.site.InfopointReason;
  73 import jdk.vm.ci.code.site.Mark;
  74 import jdk.vm.ci.meta.Constant;
  75 import jdk.vm.ci.meta.InvokeTarget;
  76 import jdk.vm.ci.meta.JavaConstant;
  77 import jdk.vm.ci.meta.JavaKind;
  78 import jdk.vm.ci.meta.VMConstant;
  79 import jdk.vm.ci.meta.Value;
  80 
  81 /**
  82  * Fills in a {@link CompilationResult} as its code is being assembled.
  83  *
  84  * @see CompilationResultBuilderFactory
  85  */
  86 public class CompilationResultBuilder {
  87 
  88     public static class Options {
  89         @Option(help = "Include the LIR as comments with the final assembly.", type = OptionType.Debug) //
  90         public static final OptionKey<Boolean> PrintLIRWithAssembly = new OptionKey<>(false);
  91     }
  92 
  93     private static class ExceptionInfo {
  94 
  95         public final int codeOffset;
  96         public final LabelRef exceptionEdge;
  97 
  98         ExceptionInfo(int pcOffset, LabelRef exceptionEdge) {
  99             this.codeOffset = pcOffset;
 100             this.exceptionEdge = exceptionEdge;
 101         }
 102     }
 103 
 104     /**
 105      * Wrapper for a code annotation that was produced by the {@link Assembler}.
 106      */
 107     public static final class AssemblerAnnotation extends CodeAnnotation {
 108 
 109         public final Assembler.CodeAnnotation assemblerCodeAnnotation;
 110 
 111         public AssemblerAnnotation(Assembler.CodeAnnotation assemblerCodeAnnotation) {
 112             super(assemblerCodeAnnotation.instructionPosition);
 113             this.assemblerCodeAnnotation = assemblerCodeAnnotation;
 114         }
 115 
 116         @Override
 117         public boolean equals(Object obj) {
 118             return this == obj;
 119         }
 120 
 121         @Override
 122         public String toString() {
 123             return assemblerCodeAnnotation.toString();
 124         }
 125     }
 126 
 127     public final Assembler asm;
 128     public final DataBuilder dataBuilder;
 129     public final CompilationResult compilationResult;
 130     public final Register uncompressedNullRegister;
 131     public final TargetDescription target;
 132     public final CodeCacheProvider codeCache;
 133     public final ForeignCallsProvider foreignCalls;
 134     public final FrameMap frameMap;
 135 
 136     /**
 137      * The LIR for which code is being generated.
 138      */
 139     protected LIR lir;
 140 
 141     /**
 142      * The index of the block currently being emitted.
 143      */
 144     protected int currentBlockIndex;
 145 
 146     /**
 147      * The object that emits code for managing a method's frame.
 148      */
 149     public final FrameContext frameContext;
 150 
 151     private List<ExceptionInfo> exceptionInfoList;
 152 
 153     private final OptionValues options;
 154     private final DebugContext debug;
 155     private final EconomicMap<Constant, Data> dataCache;
 156 
 157     private Consumer<LIRInstruction> beforeOp;
 158     private Consumer<LIRInstruction> afterOp;
 159 
 160     /**
 161      * These position maps are used for estimating offsets of forward branches. Used for
 162      * architectures where certain branch instructions have limited displacement such as ARM tbz or
 163      * SPARC cbcond.
 164      */
 165     private EconomicMap<Label, Integer> labelBindLirPositions;
 166     private EconomicMap<LIRInstruction, Integer> lirPositions;
 167     /**
 168      * This flag is for setting the
 169      * {@link CompilationResultBuilder#labelWithinRange(LIRInstruction, Label, int)} into a
 170      * conservative mode and always answering false.
 171      */
 172     private boolean conservativeLabelOffsets = false;
 173 
 174     public final boolean mustReplaceWithUncompressedNullRegister(JavaConstant nullConstant) {
 175         return !uncompressedNullRegister.equals(Register.None) && JavaConstant.NULL_POINTER.equals(nullConstant);
 176     }
 177 
 178     public CompilationResultBuilder(CodeCacheProvider codeCache,
 179                     ForeignCallsProvider foreignCalls,
 180                     FrameMap frameMap,
 181                     Assembler asm,
 182                     DataBuilder dataBuilder,
 183                     FrameContext frameContext,
 184                     OptionValues options,
 185                     DebugContext debug,
 186                     CompilationResult compilationResult,
 187                     Register uncompressedNullRegister) {
 188         this(codeCache,
 189                         foreignCalls,
 190                         frameMap,
 191                         asm,
 192                         dataBuilder,
 193                         frameContext,
 194                         options,
 195                         debug,
 196                         compilationResult,
 197                         uncompressedNullRegister,
 198                         EconomicMap.create(Equivalence.DEFAULT));
 199     }
 200 
 201     public CompilationResultBuilder(CodeCacheProvider codeCache,
 202                     ForeignCallsProvider foreignCalls,
 203                     FrameMap frameMap,
 204                     Assembler asm,
 205                     DataBuilder dataBuilder,
 206                     FrameContext frameContext,
 207                     OptionValues options,
 208                     DebugContext debug,
 209                     CompilationResult compilationResult,
 210                     Register uncompressedNullRegister,
 211                     EconomicMap<Constant, Data> dataCache) {
 212         this.target = codeCache.getTarget();
 213         this.codeCache = codeCache;
 214         this.foreignCalls = foreignCalls;
 215         this.frameMap = frameMap;
 216         this.asm = asm;
 217         this.dataBuilder = dataBuilder;
 218         this.compilationResult = compilationResult;
 219         this.uncompressedNullRegister = uncompressedNullRegister;
 220         this.frameContext = frameContext;
 221         this.options = options;
 222         this.debug = debug;
 223         assert frameContext != null;
 224         this.dataCache = dataCache;
 225     }
 226 
 227     public void setTotalFrameSize(int frameSize) {
 228         compilationResult.setTotalFrameSize(frameSize);
 229     }
 230 
 231     public void setMaxInterpreterFrameSize(int maxInterpreterFrameSize) {
 232         compilationResult.setMaxInterpreterFrameSize(maxInterpreterFrameSize);
 233     }
 234 
 235     public Mark recordMark(Object id) {
 236         return compilationResult.recordMark(asm.position(), id);
 237     }
 238 
 239     public void blockComment(String s) {
 240         compilationResult.addAnnotation(new CompilationResult.CodeComment(asm.position(), s));
 241     }
 242 
 243     /**
 244      * Sets the {@linkplain CompilationResult#setTargetCode(byte[], int) code} and
 245      * {@linkplain CompilationResult#recordExceptionHandler(int, int) exception handler} fields of
 246      * the compilation result and then {@linkplain #closeCompilationResult() closes} it.
 247      */
 248     public void finish() {
 249         int position = asm.position();
 250         compilationResult.setTargetCode(asm.close(false), position);
 251 
 252         // Record exception handlers if they exist
 253         if (exceptionInfoList != null) {
 254             for (ExceptionInfo ei : exceptionInfoList) {
 255                 int codeOffset = ei.codeOffset;
 256                 compilationResult.recordExceptionHandler(codeOffset, ei.exceptionEdge.label().position());
 257             }
 258         }
 259         closeCompilationResult();
 260     }
 261 
 262     /**
 263      * Calls {@link CompilationResult#close()} on {@link #compilationResult}.
 264      */
 265     protected void closeCompilationResult() {
 266         compilationResult.close();
 267     }
 268 
 269     public void recordExceptionHandlers(int pcOffset, LIRFrameState info) {
 270         if (info != null) {
 271             if (info.exceptionEdge != null) {
 272                 if (exceptionInfoList == null) {
 273                     exceptionInfoList = new ArrayList<>(4);
 274                 }
 275                 exceptionInfoList.add(new ExceptionInfo(pcOffset, info.exceptionEdge));
 276             }
 277         }
 278     }
 279 
 280     public void recordImplicitException(int pcOffset, LIRFrameState info) {
 281         compilationResult.recordInfopoint(pcOffset, info.debugInfo(), InfopointReason.IMPLICIT_EXCEPTION);
 282         assert info.exceptionEdge == null;
 283     }
 284 
 285     public void recordDirectCall(int posBefore, int posAfter, InvokeTarget callTarget, LIRFrameState info) {
 286         DebugInfo debugInfo = info != null ? info.debugInfo() : null;
 287         compilationResult.recordCall(posBefore, posAfter - posBefore, callTarget, debugInfo, true);
 288     }
 289 
 290     public void recordIndirectCall(int posBefore, int posAfter, InvokeTarget callTarget, LIRFrameState info) {
 291         DebugInfo debugInfo = info != null ? info.debugInfo() : null;
 292         compilationResult.recordCall(posBefore, posAfter - posBefore, callTarget, debugInfo, false);
 293     }
 294 
 295     public void recordInfopoint(int pos, LIRFrameState info, InfopointReason reason) {
 296         // infopoints always need debug info
 297         DebugInfo debugInfo = info.debugInfo();
 298         recordInfopoint(pos, debugInfo, reason);
 299     }
 300 
 301     public void recordInfopoint(int pos, DebugInfo debugInfo, InfopointReason reason) {
 302         compilationResult.recordInfopoint(pos, debugInfo, reason);
 303     }
 304 
 305     public void recordSourceMapping(int pcOffset, int endPcOffset, NodeSourcePosition sourcePosition) {
 306         compilationResult.recordSourceMapping(pcOffset, endPcOffset, sourcePosition);
 307     }
 308 
 309     public void recordInlineDataInCode(Constant data) {
 310         assert data != null;
 311         int pos = asm.position();
 312         debug.log("Inline data in code: pos = %d, data = %s", pos, data);
 313         if (data instanceof VMConstant) {
 314             compilationResult.recordDataPatch(pos, new ConstantReference((VMConstant) data));
 315         }
 316     }
 317 
 318     public void recordInlineDataInCodeWithNote(Constant data, Object note) {
 319         assert data != null;
 320         int pos = asm.position();
 321         debug.log("Inline data in code: pos = %d, data = %s, note = %s", pos, data, note);
 322         if (data instanceof VMConstant) {
 323             compilationResult.recordDataPatchWithNote(pos, new ConstantReference((VMConstant) data), note);
 324         }
 325     }
 326 
 327     public AbstractAddress recordDataSectionReference(Data data) {
 328         assert data != null;
 329         DataSectionReference reference = compilationResult.getDataSection().insertData(data);
 330         int instructionStart = asm.position();
 331         compilationResult.recordDataPatch(instructionStart, reference);
 332         return asm.getPlaceholder(instructionStart);
 333     }
 334 
 335     public AbstractAddress recordDataReferenceInCode(DataPointerConstant constant) {
 336         return recordDataReferenceInCode(constant, constant.getAlignment());
 337     }
 338 
 339     public AbstractAddress recordDataReferenceInCode(Constant constant, int alignment) {
 340         assert constant != null;
 341         debug.log("Constant reference in code: pos = %d, data = %s", asm.position(), constant);
 342         Data data = createDataItem(constant);
 343         data.updateAlignment(alignment);
 344         return recordDataSectionReference(data);
 345     }
 346 
 347     public AbstractAddress recordDataReferenceInCode(Data data, int alignment) {
 348         assert data != null;
 349         data.updateAlignment(alignment);
 350         return recordDataSectionReference(data);
 351     }
 352 
 353     public Data createDataItem(Constant constant) {
 354         Data data = dataCache.get(constant);
 355         if (data == null) {
 356             data = dataBuilder.createDataItem(constant);
 357             dataCache.put(constant, data);
 358         }
 359         return data;
 360     }
 361 
 362     public AbstractAddress recordDataReferenceInCode(byte[] data, int alignment) {
 363         assert data != null;
 364         if (debug.isLogEnabled()) {
 365             debug.log("Data reference in code: pos = %d, data = %s", asm.position(), Arrays.toString(data));
 366         }
 367         return recordDataSectionReference(new RawData(data, alignment));
 368     }
 369 
 370     /**
 371      * Notifies this object of a branch instruction at offset {@code pcOffset} in the code.
 372      *
 373      * @param isNegated negation status of the branch's condition.
 374      */
 375     @SuppressWarnings("unused")
 376     public void recordBranch(int pcOffset, boolean isNegated) {
 377     }
 378 
 379     /**
 380      * Notifies this object of a call instruction belonging to an INVOKEVIRTUAL or INVOKEINTERFACE
 381      * at offset {@code pcOffset} in the code.
 382      *
 383      * @param nodeSourcePosition source position of the corresponding invoke.
 384      */
 385     @SuppressWarnings("unused")
 386     public void recordInvokeVirtualOrInterfaceCallOp(int pcOffset, NodeSourcePosition nodeSourcePosition) {
 387     }
 388 
 389     /**
 390      * Notifies this object of a call instruction belonging to an INLINE_INVOKE at offset
 391      * {@code pcOffset} in the code.
 392      *
 393      * @param nodeSourcePosition source position of the corresponding invoke.
 394      */
 395     @SuppressWarnings("unused")
 396     public void recordInlineInvokeCallOp(int pcOffset, NodeSourcePosition nodeSourcePosition) {
 397     }
 398 
 399     /**
 400      * Returns the integer value of any constant that can be represented by a 32-bit integer value,
 401      * including long constants that fit into the 32-bit range.
 402      */
 403     public int asIntConst(Value value) {
 404         assert isJavaConstant(value) && asJavaConstant(value).getJavaKind().isNumericInteger();
 405         JavaConstant constant = asJavaConstant(value);
 406         long c = constant.asLong();
 407         if (!NumUtil.isInt(c)) {
 408             throw GraalError.shouldNotReachHere();
 409         }
 410         return (int) c;
 411     }
 412 
 413     /**
 414      * Returns the float value of any constant that can be represented by a 32-bit float value.
 415      */
 416     public float asFloatConst(Value value) {
 417         assert isJavaConstant(value) && asJavaConstant(value).getJavaKind() == JavaKind.Float;
 418         JavaConstant constant = asJavaConstant(value);
 419         return constant.asFloat();
 420     }
 421 
 422     /**
 423      * Returns the long value of any constant that can be represented by a 64-bit long value.
 424      */
 425     public long asLongConst(Value value) {
 426         assert isJavaConstant(value) && asJavaConstant(value).getJavaKind() == JavaKind.Long;
 427         JavaConstant constant = asJavaConstant(value);
 428         return constant.asLong();
 429     }
 430 
 431     /**
 432      * Returns the double value of any constant that can be represented by a 64-bit float value.
 433      */
 434     public double asDoubleConst(Value value) {
 435         assert isJavaConstant(value) && asJavaConstant(value).getJavaKind() == JavaKind.Double;
 436         JavaConstant constant = asJavaConstant(value);
 437         return constant.asDouble();
 438     }
 439 
 440     /**
 441      * Returns the address of a float constant that is embedded as a data reference into the code.
 442      */
 443     public AbstractAddress asFloatConstRef(JavaConstant value) {
 444         return asFloatConstRef(value, 4);
 445     }
 446 
 447     public AbstractAddress asFloatConstRef(JavaConstant value, int alignment) {
 448         assert value.getJavaKind() == JavaKind.Float;
 449         return recordDataReferenceInCode(value, alignment);
 450     }
 451 
 452     /**
 453      * Returns the address of a double constant that is embedded as a data reference into the code.
 454      */
 455     public AbstractAddress asDoubleConstRef(JavaConstant value) {
 456         return asDoubleConstRef(value, 8);
 457     }
 458 
 459     public AbstractAddress asDoubleConstRef(JavaConstant value, int alignment) {
 460         assert value.getJavaKind() == JavaKind.Double;
 461         return recordDataReferenceInCode(value, alignment);
 462     }
 463 
 464     /**
 465      * Returns the address of a long constant that is embedded as a data reference into the code.
 466      */
 467     public AbstractAddress asLongConstRef(JavaConstant value) {
 468         assert value.getJavaKind() == JavaKind.Long;
 469         return recordDataReferenceInCode(value, 8);
 470     }
 471 
 472     /**
 473      * Returns the address of an object constant that is embedded as a data reference into the code.
 474      */
 475     public AbstractAddress asObjectConstRef(JavaConstant value) {
 476         assert value.getJavaKind() == JavaKind.Object;
 477         return recordDataReferenceInCode(value, 8);
 478     }
 479 
 480     public AbstractAddress asByteAddr(Value value) {
 481         assert value.getPlatformKind().getSizeInBytes() >= JavaKind.Byte.getByteCount();
 482         return asAddress(value);
 483     }
 484 
 485     public AbstractAddress asShortAddr(Value value) {
 486         assert value.getPlatformKind().getSizeInBytes() >= JavaKind.Short.getByteCount();
 487         return asAddress(value);
 488     }
 489 
 490     public AbstractAddress asIntAddr(Value value) {
 491         assert value.getPlatformKind().getSizeInBytes() >= JavaKind.Int.getByteCount();
 492         return asAddress(value);
 493     }
 494 
 495     public AbstractAddress asLongAddr(Value value) {
 496         assert value.getPlatformKind().getSizeInBytes() >= JavaKind.Long.getByteCount();
 497         return asAddress(value);
 498     }
 499 
 500     public AbstractAddress asFloatAddr(Value value) {
 501         assert value.getPlatformKind().getSizeInBytes() >= JavaKind.Float.getByteCount();
 502         return asAddress(value);
 503     }
 504 
 505     public AbstractAddress asDoubleAddr(Value value) {
 506         assert value.getPlatformKind().getSizeInBytes() >= JavaKind.Double.getByteCount();
 507         return asAddress(value);
 508     }
 509 
 510     public AbstractAddress asAddress(Value value) {
 511         assert isStackSlot(value);
 512         StackSlot slot = asStackSlot(value);
 513         return asm.makeAddress(frameMap.getRegisterConfig().getFrameRegister(), frameMap.offsetForStackSlot(slot));
 514     }
 515 
 516     /**
 517      * Determines if a given edge from the block currently being emitted goes to its lexical
 518      * successor.
 519      */
 520     public boolean isSuccessorEdge(LabelRef edge) {
 521         assert lir != null;
 522         AbstractBlockBase<?>[] order = lir.codeEmittingOrder();
 523         assert order[currentBlockIndex] == edge.getSourceBlock();
 524         AbstractBlockBase<?> nextBlock = LIR.getNextBlock(order, currentBlockIndex);
 525         return nextBlock == edge.getTargetBlock();
 526     }
 527 
 528     /**
 529      * Emits code for {@code lir} in its {@linkplain LIR#codeEmittingOrder() code emitting order}.
 530      */
 531     public void emit(@SuppressWarnings("hiding") LIR lir) {
 532         assert this.lir == null;
 533         assert currentBlockIndex == 0;
 534         this.lir = lir;
 535         this.currentBlockIndex = 0;
 536         frameContext.enter(this);
 537         for (AbstractBlockBase<?> b : lir.codeEmittingOrder()) {
 538             assert (b == null && lir.codeEmittingOrder()[currentBlockIndex] == null) || lir.codeEmittingOrder()[currentBlockIndex].equals(b);
 539             emitBlock(b);
 540             currentBlockIndex++;
 541         }
 542         this.lir = null;
 543         this.currentBlockIndex = 0;
 544     }
 545 
 546     private void emitBlock(AbstractBlockBase<?> block) {
 547         if (block == null) {
 548             return;
 549         }
 550         boolean emitComment = debug.isDumpEnabled(DebugContext.BASIC_LEVEL) || Options.PrintLIRWithAssembly.getValue(getOptions());
 551         if (emitComment) {
 552             blockComment(String.format("block B%d %s", block.getId(), block.getLoop()));
 553         }
 554 
 555         for (LIRInstruction op : lir.getLIRforBlock(block)) {
 556             if (emitComment) {
 557                 blockComment(String.format("%d %s", op.id(), op));
 558             }
 559 
 560             try {
 561                 if (beforeOp != null) {
 562                     beforeOp.accept(op);
 563                 }
 564                 emitOp(this, op);
 565                 if (afterOp != null) {
 566                     afterOp.accept(op);
 567                 }
 568             } catch (GraalError e) {
 569                 throw e.addContext("lir instruction", block + "@" + op.id() + " " + op.getClass().getName() + " " + op + "\n" + Arrays.toString(lir.codeEmittingOrder()));
 570             }
 571         }
 572     }
 573 
 574     private static void emitOp(CompilationResultBuilder crb, LIRInstruction op) {
 575         try {
 576             int start = crb.asm.position();
 577             op.emitCode(crb);
 578             if (op.getPosition() != null) {
 579                 crb.recordSourceMapping(start, crb.asm.position(), op.getPosition());
 580             }
 581         } catch (BailoutException e) {
 582             throw e;
 583         } catch (AssertionError t) {
 584             throw new GraalError(t);
 585         } catch (RuntimeException t) {
 586             throw new GraalError(t);
 587         }
 588     }
 589 
 590     public void resetForEmittingCode() {
 591         asm.reset();
 592         compilationResult.resetForEmittingCode();
 593         if (exceptionInfoList != null) {
 594             exceptionInfoList.clear();
 595         }
 596         if (dataCache != null) {
 597             dataCache.clear();
 598         }
 599         lir = null;
 600         currentBlockIndex = 0;
 601     }
 602 
 603     public void setOpCallback(Consumer<LIRInstruction> beforeOp, Consumer<LIRInstruction> afterOp) {
 604         this.beforeOp = beforeOp;
 605         this.afterOp = afterOp;
 606     }
 607 
 608     public OptionValues getOptions() {
 609         return options;
 610     }
 611 
 612     /**
 613      * Builds up a map for label and LIR instruction positions where labels are or labels pointing
 614      * to.
 615      */
 616     public void buildLabelOffsets(LIR generatedLIR) {
 617         labelBindLirPositions = EconomicMap.create(Equivalence.IDENTITY);
 618         lirPositions = EconomicMap.create(Equivalence.IDENTITY);
 619         int instructionPosition = 0;
 620         for (AbstractBlockBase<?> block : generatedLIR.codeEmittingOrder()) {
 621             if (block != null) {
 622                 for (LIRInstruction op : generatedLIR.getLIRforBlock(block)) {
 623                     if (op instanceof LabelHoldingOp) {
 624                         Label label = ((LabelHoldingOp) op).getLabel();
 625                         if (label != null) {
 626                             labelBindLirPositions.put(label, instructionPosition);
 627                         }
 628                     }
 629                     lirPositions.put(op, instructionPosition);
 630                     instructionPosition++;
 631                 }
 632             }
 633         }
 634     }
 635 
 636     /**
 637      * Answers the code generator whether the jump from instruction to label is within disp LIR
 638      * instructions.
 639      *
 640      * @param disp Maximum number of LIR instructions between label and instruction
 641      */
 642     public boolean labelWithinRange(LIRInstruction instruction, Label label, int disp) {
 643         if (conservativeLabelOffsets) {
 644             return false;
 645         }
 646         Integer labelPosition = labelBindLirPositions.get(label);
 647         Integer instructionPosition = lirPositions.get(instruction);
 648         boolean result;
 649         if (labelPosition != null && instructionPosition != null) {
 650             result = Math.abs(labelPosition - instructionPosition) < disp;
 651         } else {
 652             result = false;
 653         }
 654         return result;
 655     }
 656 
 657     /**
 658      * Sets this CompilationResultBuilder into conservative mode. If set,
 659      * {@link CompilationResultBuilder#labelWithinRange(LIRInstruction, Label, int)} always returns
 660      * false.
 661      */
 662     public void setConservativeLabelRanges() {
 663         this.conservativeLabelOffsets = true;
 664     }
 665 }