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 }