Mercurial > hg > graal-compiler
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 } |