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