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