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 }