comparison graal/com.oracle.jvmci.code/src/com/oracle/jvmci/code/CompilationResult.java @ 21556:48c1ebd24120

renamed com.oracle.graal.api[meta|code] modules to com.oracle.jvmci.[meta|code] (JBS:GRAAL-53)
author Doug Simon <doug.simon@oracle.com>
date Wed, 27 May 2015 00:36:16 +0200
parents graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CompilationResult.java@082417ac43e4
children ce2113326bc8
comparison
equal deleted inserted replaced
21555:d12eaef9af72 21556:48c1ebd24120
1 /*
2 * Copyright (c) 2009, 2014, 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 package com.oracle.jvmci.code;
24
25 import static com.oracle.jvmci.meta.MetaUtil.*;
26 import static java.util.Collections.*;
27
28 import java.util.*;
29
30 import com.oracle.jvmci.code.CodeUtil.RefMapFormatter;
31 import com.oracle.jvmci.meta.Assumptions.Assumption;
32 import com.oracle.jvmci.meta.*;
33
34 /**
35 * Represents the output from compiling a method, including the compiled machine code, associated
36 * data and references, relocation information, deoptimization information, etc.
37 */
38 public class CompilationResult {
39
40 /**
41 * Represents a code position with associated additional information.
42 */
43 public abstract static class Site {
44
45 /**
46 * The position (or offset) of this site with respect to the start of the target method.
47 */
48 public final int pcOffset;
49
50 public Site(int pos) {
51 this.pcOffset = pos;
52 }
53
54 @Override
55 public final int hashCode() {
56 throw new UnsupportedOperationException("hashCode");
57 }
58
59 @Override
60 public String toString() {
61 return identityHashCodeString(this);
62 }
63
64 @Override
65 public abstract boolean equals(Object obj);
66 }
67
68 /**
69 * Represents an infopoint with associated debug info. Note that safepoints are also infopoints.
70 */
71 public static class Infopoint extends Site implements Comparable<Infopoint> {
72
73 public final DebugInfo debugInfo;
74
75 public final InfopointReason reason;
76
77 public Infopoint(int pcOffset, DebugInfo debugInfo, InfopointReason reason) {
78 super(pcOffset);
79 this.debugInfo = debugInfo;
80 this.reason = reason;
81 }
82
83 @Override
84 public String toString() {
85 StringBuilder sb = new StringBuilder();
86 sb.append(pcOffset);
87 sb.append("[<infopoint>]");
88 appendDebugInfo(sb, debugInfo);
89 return sb.toString();
90 }
91
92 @Override
93 public int compareTo(Infopoint o) {
94 if (pcOffset < o.pcOffset) {
95 return -1;
96 } else if (pcOffset > o.pcOffset) {
97 return 1;
98 }
99 return this.reason.compareTo(o.reason);
100 }
101
102 @Override
103 public boolean equals(Object obj) {
104 if (this == obj) {
105 return true;
106 }
107 if (obj != null && obj.getClass() == getClass()) {
108 Infopoint that = (Infopoint) obj;
109 if (this.pcOffset == that.pcOffset && Objects.equals(this.debugInfo, that.debugInfo) && Objects.equals(this.reason, that.reason)) {
110 return true;
111 }
112 }
113 return false;
114 }
115 }
116
117 /**
118 * Represents a call in the code.
119 */
120 public static final class Call extends Infopoint {
121
122 /**
123 * The target of the call.
124 */
125 public final InvokeTarget target;
126
127 /**
128 * The size of the call instruction.
129 */
130 public final int size;
131
132 /**
133 * Specifies if this call is direct or indirect. A direct call has an immediate operand
134 * encoding the absolute or relative (to the call itself) address of the target. An indirect
135 * call has a register or memory operand specifying the target address of the call.
136 */
137 public final boolean direct;
138
139 public Call(InvokeTarget target, int pcOffset, int size, boolean direct, DebugInfo debugInfo) {
140 super(pcOffset, debugInfo, InfopointReason.CALL);
141 this.size = size;
142 this.target = target;
143 this.direct = direct;
144 }
145
146 @Override
147 public boolean equals(Object obj) {
148 if (this == obj) {
149 return true;
150 }
151 if (obj instanceof Call && super.equals(obj)) {
152 Call that = (Call) obj;
153 if (this.size == that.size && this.direct == that.direct && Objects.equals(this.target, that.target)) {
154 return true;
155 }
156 }
157 return false;
158 }
159
160 @Override
161 public String toString() {
162 StringBuilder sb = new StringBuilder();
163 sb.append(pcOffset);
164 sb.append('[');
165 sb.append(target);
166 sb.append(']');
167
168 if (debugInfo != null) {
169 appendDebugInfo(sb, debugInfo);
170 }
171
172 return sb.toString();
173 }
174 }
175
176 /**
177 * Represents some external data that is referenced by the code.
178 */
179 public abstract static class Reference {
180
181 @Override
182 public abstract int hashCode();
183
184 @Override
185 public abstract boolean equals(Object obj);
186 }
187
188 public static final class ConstantReference extends Reference {
189
190 private final VMConstant constant;
191
192 public ConstantReference(VMConstant constant) {
193 this.constant = constant;
194 }
195
196 public VMConstant getConstant() {
197 return constant;
198 }
199
200 @Override
201 public String toString() {
202 return constant.toString();
203 }
204
205 @Override
206 public int hashCode() {
207 return constant.hashCode();
208 }
209
210 @Override
211 public boolean equals(Object obj) {
212 if (this == obj) {
213 return true;
214 }
215 if (obj instanceof ConstantReference) {
216 ConstantReference that = (ConstantReference) obj;
217 return Objects.equals(this.constant, that.constant);
218 }
219 return false;
220 }
221 }
222
223 public static final class DataSectionReference extends Reference {
224
225 private boolean initialized;
226 private int offset;
227
228 public DataSectionReference() {
229 // will be set after the data section layout is fixed
230 offset = 0xDEADDEAD;
231 }
232
233 public int getOffset() {
234 assert initialized;
235
236 return offset;
237 }
238
239 public void setOffset(int offset) {
240 assert !initialized;
241 initialized = true;
242
243 this.offset = offset;
244 }
245
246 @Override
247 public int hashCode() {
248 return offset;
249 }
250
251 @Override
252 public boolean equals(Object obj) {
253 if (this == obj) {
254 return true;
255 }
256 if (obj instanceof DataSectionReference) {
257 DataSectionReference that = (DataSectionReference) obj;
258 return this.offset == that.offset;
259 }
260 return false;
261 }
262 }
263
264 /**
265 * Represents a code site that references some data. The associated data can be either a
266 * {@link DataSectionReference reference} to the data section, or it may be an inlined
267 * {@link JavaConstant} that needs to be patched.
268 */
269 public static final class DataPatch extends Site {
270
271 public Reference reference;
272
273 public DataPatch(int pcOffset, Reference reference) {
274 super(pcOffset);
275 this.reference = reference;
276 }
277
278 @Override
279 public String toString() {
280 return String.format("%d[<data patch referring to %s>]", pcOffset, reference.toString());
281 }
282
283 @Override
284 public boolean equals(Object obj) {
285 if (this == obj) {
286 return true;
287 }
288 if (obj instanceof DataPatch) {
289 DataPatch that = (DataPatch) obj;
290 if (this.pcOffset == that.pcOffset && Objects.equals(this.reference, that.reference)) {
291 return true;
292 }
293 }
294 return false;
295 }
296 }
297
298 /**
299 * Provides extra information about instructions or data at specific positions in
300 * {@link CompilationResult#getTargetCode()}. This is optional information that can be used to
301 * enhance a disassembly of the code.
302 */
303 public abstract static class CodeAnnotation {
304
305 public final int position;
306
307 public CodeAnnotation(int position) {
308 this.position = position;
309 }
310
311 @Override
312 public final int hashCode() {
313 throw new UnsupportedOperationException("hashCode");
314 }
315
316 @Override
317 public String toString() {
318 return identityHashCodeString(this);
319 }
320
321 @Override
322 public abstract boolean equals(Object obj);
323 }
324
325 /**
326 * A string comment about one or more instructions at a specific position in the code.
327 */
328 public static final class CodeComment extends CodeAnnotation {
329
330 public final String value;
331
332 public CodeComment(int position, String comment) {
333 super(position);
334 this.value = comment;
335 }
336
337 @Override
338 public boolean equals(Object obj) {
339 if (this == obj) {
340 return true;
341 }
342 if (obj instanceof CodeComment) {
343 CodeComment that = (CodeComment) obj;
344 if (this.position == that.position && this.value.equals(that.value)) {
345 return true;
346 }
347 }
348 return false;
349 }
350
351 @Override
352 public String toString() {
353 return getClass().getSimpleName() + "@" + position + ": " + value;
354 }
355 }
356
357 /**
358 * Describes a table of signed offsets embedded in the code. The offsets are relative to the
359 * starting address of the table. This type of table maybe generated when translating a
360 * multi-way branch based on a key value from a dense value set (e.g. the {@code tableswitch}
361 * JVM instruction).
362 *
363 * The table is indexed by the contiguous range of integers from {@link #low} to {@link #high}
364 * inclusive.
365 */
366 public static final class JumpTable extends CodeAnnotation {
367
368 /**
369 * The low value in the key range (inclusive).
370 */
371 public final int low;
372
373 /**
374 * The high value in the key range (inclusive).
375 */
376 public final int high;
377
378 /**
379 * The size (in bytes) of each table entry.
380 */
381 public final int entrySize;
382
383 public JumpTable(int position, int low, int high, int entrySize) {
384 super(position);
385 this.low = low;
386 this.high = high;
387 this.entrySize = entrySize;
388 }
389
390 @Override
391 public boolean equals(Object obj) {
392 if (this == obj) {
393 return true;
394 }
395 if (obj instanceof JumpTable) {
396 JumpTable that = (JumpTable) obj;
397 if (this.position == that.position && this.entrySize == that.entrySize && this.low == that.low && this.high == that.high) {
398 return true;
399 }
400 }
401 return false;
402 }
403
404 @Override
405 public String toString() {
406 return getClass().getSimpleName() + "@" + position + ": [" + low + " .. " + high + "]";
407 }
408 }
409
410 /**
411 * Represents exception handler information for a specific code position. It includes the catch
412 * code position as well as the caught exception type.
413 */
414 public static final class ExceptionHandler extends Site {
415
416 public final int handlerPos;
417
418 ExceptionHandler(int pcOffset, int handlerPos) {
419 super(pcOffset);
420 this.handlerPos = handlerPos;
421 }
422
423 @Override
424 public String toString() {
425 return String.format("%d[<exception edge to %d>]", pcOffset, handlerPos);
426 }
427
428 @Override
429 public boolean equals(Object obj) {
430 if (this == obj) {
431 return true;
432 }
433 if (obj instanceof ExceptionHandler) {
434 ExceptionHandler that = (ExceptionHandler) obj;
435 if (this.pcOffset == that.pcOffset && this.handlerPos == that.handlerPos) {
436 return true;
437 }
438 }
439 return false;
440 }
441 }
442
443 /**
444 * Represents a mark in the machine code that can be used by the runtime for its own purposes. A
445 * mark can reference other marks.
446 */
447 public static final class Mark extends Site {
448
449 public final Object id;
450
451 public Mark(int pcOffset, Object id) {
452 super(pcOffset);
453 this.id = id;
454 }
455
456 @Override
457 public String toString() {
458 if (id == null) {
459 return String.format("%d[<mar>]", pcOffset);
460 } else if (id instanceof Integer) {
461 return String.format("%d[<mark with id %s>]", pcOffset, Integer.toHexString((Integer) id));
462 } else {
463 return String.format("%d[<mark with id %s>]", pcOffset, id.toString());
464 }
465 }
466
467 @Override
468 public boolean equals(Object obj) {
469 if (this == obj) {
470 return true;
471 }
472 if (obj instanceof Mark) {
473 Mark that = (Mark) obj;
474 if (this.pcOffset == that.pcOffset && Objects.equals(this.id, that.id)) {
475 return true;
476 }
477 }
478 return false;
479 }
480 }
481
482 private int id = -1;
483 private int entryBCI = -1;
484
485 private final DataSection dataSection = new DataSection();
486
487 private final List<Infopoint> infopoints = new ArrayList<>();
488 private final List<DataPatch> dataPatches = new ArrayList<>();
489 private final List<ExceptionHandler> exceptionHandlers = new ArrayList<>();
490 private final List<Mark> marks = new ArrayList<>();
491
492 private int totalFrameSize = -1;
493 private int customStackAreaOffset = -1;
494
495 private final String name;
496
497 /**
498 * The buffer containing the emitted machine code.
499 */
500 private byte[] targetCode;
501
502 /**
503 * The leading number of bytes in {@link #targetCode} containing the emitted machine code.
504 */
505 private int targetCodeSize;
506
507 private ArrayList<CodeAnnotation> annotations;
508
509 private Assumption[] assumptions;
510
511 /**
512 * The list of the methods whose bytecodes were used as input to the compilation. If
513 * {@code null}, then the compilation did not record method dependencies. Otherwise, the first
514 * element of this array is the root method of the compilation.
515 */
516 private ResolvedJavaMethod[] methods;
517
518 public CompilationResult() {
519 this(null);
520 }
521
522 public CompilationResult(String name) {
523 this.name = name;
524 }
525
526 @Override
527 public int hashCode() {
528 // CompilationResult instances should not be used as hash map keys
529 throw new UnsupportedOperationException("hashCode");
530 }
531
532 @Override
533 public String toString() {
534 if (methods != null) {
535 return getClass().getName() + "[" + methods[0].format("%H.%n(%p)%r") + "]";
536 }
537 return identityHashCodeString(this);
538 }
539
540 @Override
541 public boolean equals(Object obj) {
542 if (this == obj) {
543 return true;
544 }
545 if (obj != null && obj.getClass() == getClass()) {
546 CompilationResult that = (CompilationResult) obj;
547 // @formatter:off
548 if (this.entryBCI == that.entryBCI &&
549 this.id == that.id &&
550 this.customStackAreaOffset == that.customStackAreaOffset &&
551 this.totalFrameSize == that.totalFrameSize &&
552 this.targetCodeSize == that.targetCodeSize &&
553 Objects.equals(this.name, that.name) &&
554 Objects.equals(this.annotations, that.annotations) &&
555 Objects.equals(this.dataSection, that.dataSection) &&
556 Objects.equals(this.exceptionHandlers, that.exceptionHandlers) &&
557 Objects.equals(this.dataPatches, that.dataPatches) &&
558 Objects.equals(this.infopoints, that.infopoints) &&
559 Objects.equals(this.marks, that.marks) &&
560 Arrays.equals(this.assumptions, that.assumptions) &&
561 Arrays.equals(targetCode, that.targetCode)) {
562 return true;
563 }
564 // @formatter:on
565 }
566 return false;
567 }
568
569 /**
570 * @return the compile id
571 */
572 public int getId() {
573 return id;
574 }
575
576 /**
577 * @param id the compile id to set
578 */
579 public void setId(int id) {
580 this.id = id;
581 }
582
583 /**
584 * @return the entryBCI
585 */
586 public int getEntryBCI() {
587 return entryBCI;
588 }
589
590 /**
591 * @param entryBCI the entryBCI to set
592 */
593 public void setEntryBCI(int entryBCI) {
594 this.entryBCI = entryBCI;
595 }
596
597 /**
598 * Sets the assumptions made during compilation.
599 */
600 public void setAssumptions(Assumption[] assumptions) {
601 this.assumptions = assumptions;
602 }
603
604 /**
605 * Gets a fixed-size {@linkplain Arrays#asList(Object...) view} of the assumptions made during
606 * compilation.
607 */
608 public Collection<Assumption> getAssumptions() {
609 return assumptions == null ? Collections.emptyList() : Arrays.asList(assumptions);
610 }
611
612 /**
613 * Sets the methods whose bytecodes were used as input to the compilation.
614 *
615 * @param rootMethod the root method of the compilation
616 * @param inlinedMethods the methods inlined during compilation
617 */
618 public void setMethods(ResolvedJavaMethod rootMethod, Collection<ResolvedJavaMethod> inlinedMethods) {
619 assert rootMethod != null;
620 assert inlinedMethods != null;
621 if (inlinedMethods.contains(rootMethod)) {
622 methods = inlinedMethods.toArray(new ResolvedJavaMethod[inlinedMethods.size()]);
623 for (int i = 0; i < methods.length; i++) {
624 if (methods[i].equals(rootMethod)) {
625 if (i != 0) {
626 ResolvedJavaMethod tmp = methods[0];
627 methods[0] = methods[i];
628 methods[i] = tmp;
629 }
630 break;
631 }
632 }
633 } else {
634 methods = new ResolvedJavaMethod[1 + inlinedMethods.size()];
635 methods[0] = rootMethod;
636 int i = 1;
637 for (ResolvedJavaMethod m : inlinedMethods) {
638 methods[i++] = m;
639 }
640 }
641 }
642
643 /**
644 * Gets a fixed-size {@linkplain Arrays#asList(Object...) view} of the methods whose bytecodes
645 * were used as input to the compilation.
646 *
647 * @return {@code null} if the compilation did not record method dependencies otherwise the
648 * methods whose bytecodes were used as input to the compilation with the first element
649 * being the root method of the compilation
650 */
651 public Collection<ResolvedJavaMethod> getMethods() {
652 return methods == null ? null : Arrays.asList(methods);
653 }
654
655 public DataSection getDataSection() {
656 return dataSection;
657 }
658
659 /**
660 * The total frame size of the method in bytes. This includes the return address pushed onto the
661 * stack, if any.
662 *
663 * @return the frame size
664 */
665 public int getTotalFrameSize() {
666 assert totalFrameSize != -1 : "frame size not yet initialized!";
667 return totalFrameSize;
668 }
669
670 /**
671 * Sets the total frame size in bytes. This includes the return address pushed onto the stack,
672 * if any.
673 *
674 * @param size the size of the frame in bytes
675 */
676 public void setTotalFrameSize(int size) {
677 totalFrameSize = size;
678 }
679
680 /**
681 * Sets the machine that has been generated by the compiler.
682 *
683 * @param code the machine code generated
684 * @param size the size of the machine code
685 */
686 public void setTargetCode(byte[] code, int size) {
687 targetCode = code;
688 targetCodeSize = size;
689 }
690
691 /**
692 * Records a data patch in the code section. The data patch can refer to something in the
693 * {@link DataSectionReference data section} or directly to an {@link ConstantReference inlined
694 * constant}.
695 *
696 * @param codePos The position in the code that needs to be patched.
697 * @param ref The reference that should be inserted in the code.
698 */
699 public void recordDataPatch(int codePos, Reference ref) {
700 assert codePos >= 0 && ref != null;
701 dataPatches.add(new DataPatch(codePos, ref));
702 }
703
704 /**
705 * Records a call in the code array.
706 *
707 * @param codePos the position of the call in the code array
708 * @param size the size of the call instruction
709 * @param target the being called
710 * @param debugInfo the debug info for the call
711 * @param direct specifies if this is a {@linkplain Call#direct direct} call
712 */
713 public void recordCall(int codePos, int size, InvokeTarget target, DebugInfo debugInfo, boolean direct) {
714 final Call call = new Call(target, codePos, size, direct, debugInfo);
715 addInfopoint(call);
716 }
717
718 /**
719 * Records an exception handler for this method.
720 *
721 * @param codePos the position in the code that is covered by the handler
722 * @param handlerPos the position of the handler
723 */
724 public void recordExceptionHandler(int codePos, int handlerPos) {
725 assert validateExceptionHandlerAdd(codePos, handlerPos) : String.format("Duplicate exception handler for pc 0x%x handlerPos 0x%x", codePos, handlerPos);
726 exceptionHandlers.add(new ExceptionHandler(codePos, handlerPos));
727 }
728
729 /**
730 * Validate if the exception handler for codePos already exists and handlerPos is different.
731 *
732 * @param codePos
733 * @param handlerPos
734 * @return true if the validation is successful
735 */
736 private boolean validateExceptionHandlerAdd(int codePos, int handlerPos) {
737 ExceptionHandler exHandler = getExceptionHandlerForCodePos(codePos);
738 return exHandler == null || exHandler.handlerPos == handlerPos;
739 }
740
741 /**
742 * Returns the first ExceptionHandler which matches codePos.
743 *
744 * @param codePos position to search for
745 * @return first matching ExceptionHandler
746 */
747 private ExceptionHandler getExceptionHandlerForCodePos(int codePos) {
748 for (ExceptionHandler h : exceptionHandlers) {
749 if (h.pcOffset == codePos) {
750 return h;
751 }
752 }
753 return null;
754 }
755
756 /**
757 * Records an infopoint in the code array.
758 *
759 * @param codePos the position of the infopoint in the code array
760 * @param debugInfo the debug info for the infopoint
761 */
762 public void recordInfopoint(int codePos, DebugInfo debugInfo, InfopointReason reason) {
763 addInfopoint(new Infopoint(codePos, debugInfo, reason));
764 }
765
766 /**
767 * Records a custom infopoint in the code section.
768 *
769 * Compiler implementations can use this method to record non-standard infopoints, which are not
770 * handled by the dedicated methods like {@link #recordCall}.
771 *
772 * @param infopoint the infopoint to record, usually a derived class from {@link Infopoint}
773 */
774 public void addInfopoint(Infopoint infopoint) {
775 // The infopoints list must always be sorted
776 if (!infopoints.isEmpty()) {
777 Infopoint previousInfopoint = infopoints.get(infopoints.size() - 1);
778 if (previousInfopoint.pcOffset > infopoint.pcOffset) {
779 // This re-sorting should be very rare
780 Collections.sort(infopoints);
781 previousInfopoint = infopoints.get(infopoints.size() - 1);
782 }
783 if (previousInfopoint.pcOffset == infopoint.pcOffset) {
784 if (infopoint.reason.canBeOmitted()) {
785 return;
786 }
787 if (previousInfopoint.reason.canBeOmitted()) {
788 Infopoint removed = infopoints.remove(infopoints.size() - 1);
789 assert removed == previousInfopoint;
790 } else {
791 throw new RuntimeException("Infopoints that can not be omited should have distinct PCs");
792 }
793 }
794 }
795 infopoints.add(infopoint);
796 }
797
798 /**
799 * Records an instruction mark within this method.
800 *
801 * @param codePos the position in the code that is covered by the handler
802 * @param markId the identifier for this mark
803 */
804 public Mark recordMark(int codePos, Object markId) {
805 Mark mark = new Mark(codePos, markId);
806 marks.add(mark);
807 return mark;
808 }
809
810 /**
811 * Offset in bytes for the custom stack area (relative to sp).
812 *
813 * @return the offset in bytes
814 */
815 public int getCustomStackAreaOffset() {
816 return customStackAreaOffset;
817 }
818
819 /**
820 * @see #getCustomStackAreaOffset()
821 * @param offset
822 */
823 public void setCustomStackAreaOffset(int offset) {
824 customStackAreaOffset = offset;
825 }
826
827 /**
828 * @return the machine code generated for this method
829 */
830 public byte[] getTargetCode() {
831 return targetCode;
832 }
833
834 /**
835 * @return the size of the machine code generated for this method
836 */
837 public int getTargetCodeSize() {
838 return targetCodeSize;
839 }
840
841 /**
842 * @return the code annotations or {@code null} if there are none
843 */
844 public List<CodeAnnotation> getAnnotations() {
845 if (annotations == null) {
846 return Collections.emptyList();
847 }
848 return annotations;
849 }
850
851 public void addAnnotation(CodeAnnotation annotation) {
852 assert annotation != null;
853 if (annotations == null) {
854 annotations = new ArrayList<>();
855 }
856 annotations.add(annotation);
857 }
858
859 private static void appendDebugInfo(StringBuilder sb, DebugInfo info) {
860 if (info != null) {
861 ReferenceMap refMap = info.getReferenceMap();
862 if (refMap != null) {
863 RefMapFormatter formatter = new CodeUtil.NumberedRefMapFormatter();
864 if (refMap.hasFrameRefMap()) {
865 sb.append(" stackMap[");
866 refMap.appendFrameMap(sb, formatter);
867 sb.append(']');
868 }
869 if (refMap.hasRegisterRefMap()) {
870 sb.append(" registerMap[");
871 refMap.appendRegisterMap(sb, formatter);
872 sb.append(']');
873 }
874 }
875 RegisterSaveLayout calleeSaveInfo = info.getCalleeSaveInfo();
876 if (calleeSaveInfo != null) {
877 sb.append(" callee-save-info[");
878 String sep = "";
879 for (Map.Entry<Register, Integer> e : calleeSaveInfo.registersToSlots(true).entrySet()) {
880 sb.append(sep).append(e.getKey()).append("->").append(e.getValue());
881 sep = ", ";
882 }
883 sb.append(']');
884 }
885 BytecodePosition codePos = info.getBytecodePosition();
886 if (codePos != null) {
887 MetaUtil.appendLocation(sb.append(" "), codePos.getMethod(), codePos.getBCI());
888 if (info.hasFrame()) {
889 sb.append(" #locals=").append(info.frame().numLocals).append(" #expr=").append(info.frame().numStack);
890 if (info.frame().numLocks > 0) {
891 sb.append(" #locks=").append(info.frame().numLocks);
892 }
893 }
894 }
895 }
896 }
897
898 /**
899 * @return the list of infopoints, sorted by {@link Site#pcOffset}
900 */
901 public List<Infopoint> getInfopoints() {
902 if (infopoints.isEmpty()) {
903 return emptyList();
904 }
905 return unmodifiableList(infopoints);
906 }
907
908 /**
909 * @return the list of data references
910 */
911 public List<DataPatch> getDataPatches() {
912 if (dataPatches.isEmpty()) {
913 return emptyList();
914 }
915 return unmodifiableList(dataPatches);
916 }
917
918 /**
919 * @return the list of exception handlers
920 */
921 public List<ExceptionHandler> getExceptionHandlers() {
922 if (exceptionHandlers.isEmpty()) {
923 return emptyList();
924 }
925 return unmodifiableList(exceptionHandlers);
926 }
927
928 /**
929 * @return the list of marks
930 */
931 public List<Mark> getMarks() {
932 if (marks.isEmpty()) {
933 return emptyList();
934 }
935 return unmodifiableList(marks);
936 }
937
938 public String getName() {
939 return name;
940 }
941
942 public void reset() {
943 infopoints.clear();
944 dataPatches.clear();
945 exceptionHandlers.clear();
946 marks.clear();
947 if (annotations != null) {
948 annotations.clear();
949 }
950 }
951 }