Mercurial > hg > graal-compiler
comparison graal/com.oracle.jvmci.hotspot/src/com/oracle/jvmci/hotspot/HotSpotReferenceMap.java @ 21730:b9f9b8af17ff
Simplify interface to reference map
author | Tom Rodriguez <tom.rodriguez@oracle.com> |
---|---|
date | Wed, 03 Jun 2015 19:57:38 -0700 |
parents | 48c1ebd24120 |
children | df9d2375512a |
comparison
equal
deleted
inserted
replaced
21729:e7f5ddef438d | 21730:b9f9b8af17ff |
---|---|
20 * or visit www.oracle.com if you need additional information or have any | 20 * or visit www.oracle.com if you need additional information or have any |
21 * questions. | 21 * questions. |
22 */ | 22 */ |
23 package com.oracle.jvmci.hotspot; | 23 package com.oracle.jvmci.hotspot; |
24 | 24 |
25 import static com.oracle.jvmci.code.ValueUtil.*; | |
26 | |
25 import java.util.*; | 27 import java.util.*; |
26 | 28 |
27 import com.oracle.jvmci.code.CodeUtil.RefMapFormatter; | |
28 import com.oracle.jvmci.code.*; | 29 import com.oracle.jvmci.code.*; |
29 import com.oracle.jvmci.common.*; | |
30 import com.oracle.jvmci.meta.*; | 30 import com.oracle.jvmci.meta.*; |
31 | 31 |
32 public final class HotSpotReferenceMap extends ReferenceMap { | 32 public final class HotSpotReferenceMap extends ReferenceMap { |
33 | 33 |
34 static final int OOP64 = 0b1010; | 34 private Value[] objects; |
35 static final int OOP32 = 0b01; | 35 private int[] bytesPerElement; |
36 static final int NARROW_LOW = OOP32; | 36 private ArrayList<Value> objectValues; |
37 static final int NARROW_HIGH = OOP32 << 2; | |
38 static final int NARROW_BOTH = NARROW_LOW | NARROW_HIGH; | |
39 | 37 |
40 private enum MapEntry { | 38 private final TargetDescription target; |
41 NoReference(0), | |
42 WideOop(OOP64), | |
43 NarrowOopLowerHalf(NARROW_LOW), | |
44 NarrowOopUpperHalf(NARROW_HIGH), | |
45 TwoNarrowOops(NARROW_BOTH), | |
46 Illegal(-1); | |
47 | 39 |
48 MapEntry(int pattern) { | 40 public HotSpotReferenceMap(TargetDescription target) { |
49 this.pattern = pattern; | 41 this.target = target; |
42 this.objects = Value.NO_VALUES; | |
43 } | |
44 | |
45 @Override | |
46 public void reset() { | |
47 objectValues = new ArrayList<>(); | |
48 objects = Value.NO_VALUES; | |
49 bytesPerElement = null; | |
50 } | |
51 | |
52 @Override | |
53 public void addLiveValue(Value v) { | |
54 if (isConstant(v)) { | |
55 return; | |
50 } | 56 } |
51 | 57 LIRKind lirKind = v.getLIRKind(); |
52 final int pattern; | 58 if (!lirKind.isValue()) { |
53 | 59 objectValues.add(v); |
54 /** | |
55 * Create enum values from OopMap. | |
56 * <p> | |
57 * These bits can have the following values (MSB first): | |
58 * | |
59 * <pre> | |
60 * 0000 - contains no references | |
61 * 1010 - contains a wide oop | |
62 * 0001 - contains a narrow oop in the lower half | |
63 * 0101 - contains a narrow oop in the upper half | |
64 * 0101 - contains two narrow oops | |
65 * </pre> | |
66 * | |
67 * @see HotSpotReferenceMap#registerRefMap | |
68 * @see HotSpotReferenceMap#frameRefMap | |
69 */ | |
70 static MapEntry getFromBits(int idx, HotSpotOopMap set) { | |
71 int n = set.get(idx); | |
72 switch (n) { | |
73 case 0: | |
74 return NoReference; | |
75 case OOP64: | |
76 return WideOop; | |
77 case NARROW_LOW: | |
78 return NarrowOopLowerHalf; | |
79 case NARROW_HIGH: | |
80 return NarrowOopUpperHalf; | |
81 case NARROW_BOTH: | |
82 return TwoNarrowOops; | |
83 default: | |
84 return Illegal; | |
85 } | |
86 } | |
87 | |
88 String toBitString() { | |
89 int bits = toBit(this); | |
90 if (bits == -1) { | |
91 return "---"; | |
92 } | |
93 return String.format("%3s", Integer.toBinaryString(bits)).replace(' ', '0'); | |
94 } | |
95 | |
96 static int toBit(MapEntry type) { | |
97 return type.pattern; | |
98 } | 60 } |
99 } | 61 } |
100 | 62 |
101 /** | 63 @Override |
102 * A specialized bit set that represents both wide and narrow oops in an efficient manner. The | 64 public void finish() { |
103 * map consists of 4 bit entries that represent 8 bytes of memory. | 65 objects = objectValues.toArray(new Value[objectValues.size()]); |
104 * | 66 this.bytesPerElement = new int[objects.length]; |
105 */ | 67 for (int i = 0; i < objects.length; i++) { |
106 class HotSpotOopMap implements Cloneable { | 68 bytesPerElement[i] = bytesPerElement(objects[i].getLIRKind()); |
107 | |
108 /** | |
109 * Each entry is 4 bits long and covers 8 bytes of memory. | |
110 */ | |
111 private static final int BITS_PER_ENTRY = 4; | |
112 private static final int BITS_PER_ELEMENT = 64; | |
113 | |
114 public HotSpotOopMap(int i) { | |
115 words = new long[(i * BITS_PER_ENTRY + BITS_PER_ELEMENT) / BITS_PER_ELEMENT]; | |
116 } | 69 } |
117 | 70 objectValues = null; |
118 public HotSpotOopMap(HotSpotOopMap other) { | |
119 words = other.words.clone(); | |
120 } | |
121 | |
122 private long[] words; | |
123 | |
124 private int get(int i) { | |
125 return getEntry(i); | |
126 } | |
127 | |
128 public void or(HotSpotOopMap src) { | |
129 if (words.length < src.words.length) { | |
130 long[] newWords = new long[src.words.length]; | |
131 System.arraycopy(src.words, 0, newWords, 0, src.words.length); | |
132 for (int i = 0; i < words.length; i++) { | |
133 newWords[i] |= words[i]; | |
134 } | |
135 words = newWords; | |
136 } else { | |
137 for (int i = 0; i < src.words.length; i++) { | |
138 words[i] |= src.words[i]; | |
139 } | |
140 } | |
141 } | |
142 | |
143 private void setOop(int regIdx) { | |
144 setEntry(regIdx, OOP64); | |
145 } | |
146 | |
147 public int size() { | |
148 return words.length * BITS_PER_ELEMENT / BITS_PER_ENTRY; | |
149 } | |
150 | |
151 @Override | |
152 public HotSpotOopMap clone() { | |
153 return new HotSpotOopMap(this); | |
154 } | |
155 | |
156 private void setNarrowOop(int offset) { | |
157 setNarrowEntry(offset, OOP32); | |
158 } | |
159 | |
160 private void setEntry(int regIdx, int value) { | |
161 assert regIdx % 2 == 0 : "must be alinged"; | |
162 int bitIndex = (regIdx >> 1) * BITS_PER_ENTRY; | |
163 int wordIndex = bitIndex / BITS_PER_ELEMENT; | |
164 int shift = bitIndex - wordIndex * BITS_PER_ELEMENT; | |
165 if (wordIndex >= words.length) { | |
166 if (value == 0) { | |
167 // Nothing to do since bits are clear | |
168 return; | |
169 } | |
170 words = Arrays.copyOf(words, wordIndex + 1); | |
171 } | |
172 assert verifyUpdate(this, this); | |
173 long orig = words[wordIndex]; | |
174 words[wordIndex] = (orig & (~(0b1111L << shift))) | ((long) value << shift); | |
175 assert get(regIdx / 2) == value; | |
176 assert verifyUpdate(this, this); | |
177 } | |
178 | |
179 private void setNarrowEntry(int offset, int value) { | |
180 int regIdx = offset >> 1; | |
181 boolean low = offset % 2 == 0; | |
182 int bitIndex = regIdx * BITS_PER_ENTRY; | |
183 int wordIndex = bitIndex / BITS_PER_ELEMENT; | |
184 int shift = bitIndex - wordIndex * BITS_PER_ELEMENT; | |
185 if (wordIndex >= words.length) { | |
186 if (value == 0) { | |
187 // Nothing to do since bits are clear | |
188 return; | |
189 } | |
190 words = Arrays.copyOf(words, wordIndex + 1); | |
191 } | |
192 long originalValue = words[wordIndex]; | |
193 int current = ((int) (originalValue >> shift)) & 0b1111; | |
194 if (current == OOP64) { | |
195 current = 0; | |
196 } | |
197 long newValue; | |
198 if (value != 0) { | |
199 newValue = current | (low ? value : (value << 2)); | |
200 } else { | |
201 newValue = current & (low ? 0b1100 : 0b0011); | |
202 } | |
203 long masked = originalValue & (~(0b1111L << shift)); | |
204 words[wordIndex] = masked | (newValue << shift); | |
205 assert verifyUpdate(this, this); | |
206 } | |
207 | |
208 private int getEntry(int regIdx) { | |
209 int bitIndex = regIdx * BITS_PER_ENTRY; | |
210 int wordIndex = bitIndex / BITS_PER_ELEMENT; | |
211 int shift = bitIndex - wordIndex * BITS_PER_ELEMENT; | |
212 return ((int) (words[wordIndex] >>> shift)) & 0b1111; | |
213 } | |
214 | |
215 @Override | |
216 public boolean equals(Object other) { | |
217 if (this == other) { | |
218 return true; | |
219 } | |
220 | |
221 if (other instanceof HotSpotOopMap) { | |
222 HotSpotOopMap otherMap = (HotSpotOopMap) other; | |
223 int limit = Math.min(words.length, otherMap.words.length); | |
224 for (int i = 0; i < limit; i++) { | |
225 if (words[i] != otherMap.words[i]) { | |
226 return false; | |
227 } | |
228 } | |
229 for (int i = limit; i < words.length; i++) { | |
230 if (words[i] != 0) { | |
231 return false; | |
232 } | |
233 } | |
234 for (int i = limit; i < otherMap.words.length; i++) { | |
235 if (otherMap.words[i] != 0) { | |
236 return false; | |
237 } | |
238 } | |
239 return true; | |
240 } | |
241 return false; | |
242 } | |
243 | |
244 @Override | |
245 public int hashCode() { | |
246 long h = 1234; | |
247 for (int i = words.length; --i >= 0;) { | |
248 h ^= words[i] * (i + 1); | |
249 } | |
250 return (int) ((h >> 32) ^ h); | |
251 } | |
252 | |
253 @Override | |
254 public String toString() { | |
255 int count = 0; | |
256 StringBuilder sb = new StringBuilder(); | |
257 sb.append("["); | |
258 for (int idx = 0; idx < size(); idx++) { | |
259 MapEntry dstType = MapEntry.getFromBits(idx, this); | |
260 if (dstType == MapEntry.NoReference) { | |
261 continue; | |
262 } | |
263 if (count > 0) { | |
264 sb.append(", "); | |
265 } | |
266 if (dstType == MapEntry.Illegal) { | |
267 int value = get(idx); | |
268 sb.append("0x"); | |
269 sb.append(Integer.toHexString(value)); | |
270 } else { | |
271 sb.append(idx); | |
272 sb.append(':'); | |
273 sb.append(dstType); | |
274 } | |
275 count++; | |
276 } | |
277 sb.append("]"); | |
278 return sb.toString(); | |
279 } | |
280 } | |
281 | |
282 /** | |
283 * Contains 3 bits per scalar register, and n*3 bits per n-word vector register (e.g., on a | |
284 * 64-bit system, a 256-bit vector register requires 12 reference map bits). | |
285 * <p> | |
286 * These bits can have the following values (LSB first): | |
287 * | |
288 * <pre> | |
289 * 000 - contains no references | |
290 * 100 - contains a wide oop | |
291 * 110 - contains a narrow oop in the lower half | |
292 * 101 - contains a narrow oop in the upper half | |
293 * 111 - contains two narrow oops | |
294 * </pre> | |
295 */ | |
296 private final HotSpotOopMap registerRefMap; | |
297 | |
298 /** | |
299 * Contains 3 bits per stack word. | |
300 * <p> | |
301 * These bits can have the following values (LSB first): | |
302 * | |
303 * <pre> | |
304 * 000 - contains no references | |
305 * 100 - contains a wide oop | |
306 * 110 - contains a narrow oop in the lower half | |
307 * 101 - contains a narrow oop in the upper half | |
308 * 111 - contains two narrow oops | |
309 * </pre> | |
310 */ | |
311 private final HotSpotOopMap frameRefMap; | |
312 | |
313 private final TargetDescription target; | |
314 | |
315 public HotSpotReferenceMap(int registerCount, int frameSlotCount, TargetDescription target) { | |
316 if (registerCount > 0) { | |
317 this.registerRefMap = new HotSpotOopMap(registerCount); | |
318 } else { | |
319 this.registerRefMap = null; | |
320 } | |
321 this.frameRefMap = new HotSpotOopMap(frameSlotCount); | |
322 this.target = target; | |
323 } | |
324 | |
325 private HotSpotReferenceMap(HotSpotReferenceMap other) { | |
326 this.registerRefMap = other.registerRefMap.clone(); | |
327 this.frameRefMap = other.frameRefMap.clone(); | |
328 this.target = other.target; | |
329 } | |
330 | |
331 @Override | |
332 public ReferenceMap clone() { | |
333 return new HotSpotReferenceMap(this); | |
334 } | |
335 | |
336 // setters | |
337 @Override | |
338 public void setRegister(int idx, LIRKind kind) { | |
339 set(registerRefMap, idx * 2, kind); | |
340 } | |
341 | |
342 @Override | |
343 public void setStackSlot(int offset, LIRKind kind) { | |
344 assert offset % bytesPerElement(kind) == 0 : "unaligned value in ReferenceMap"; | |
345 set(frameRefMap, offset / 4, kind); | |
346 } | |
347 | |
348 private void set(HotSpotOopMap refMap, int index, LIRKind kind) { | |
349 if (kind.isDerivedReference()) { | |
350 throw new JVMCIError("derived reference cannot be inserted in ReferenceMap"); | |
351 } | |
352 | |
353 int bytesPerElement = bytesPerElement(kind); | |
354 int length = kind.getPlatformKind().getVectorLength(); | |
355 if (bytesPerElement == 8) { | |
356 for (int i = 0; i < length; i++) { | |
357 if (kind.isReference(i)) { | |
358 refMap.setOop(index + i * 2); | |
359 } | |
360 } | |
361 } else if (bytesPerElement == 4) { | |
362 for (int i = 0; i < length; i++) { | |
363 if (kind.isReference(i)) { | |
364 refMap.setNarrowOop(index + i); | |
365 } | |
366 } | |
367 } else { | |
368 assert kind.isValue() : "unknown reference kind " + kind; | |
369 } | |
370 } | 71 } |
371 | 72 |
372 private int bytesPerElement(LIRKind kind) { | 73 private int bytesPerElement(LIRKind kind) { |
373 PlatformKind platformKind = kind.getPlatformKind(); | 74 PlatformKind platformKind = kind.getPlatformKind(); |
374 return target.getSizeInBytes(platformKind) / platformKind.getVectorLength(); | 75 return target.getSizeInBytes(platformKind) / platformKind.getVectorLength(); |
375 } | |
376 | |
377 public HotSpotOopMap getFrameMap() { | |
378 return frameRefMap == null ? null : (HotSpotOopMap) frameRefMap.clone(); | |
379 } | |
380 | |
381 public HotSpotOopMap getRegisterMap() { | |
382 return registerRefMap == null ? null : (HotSpotOopMap) registerRefMap.clone(); | |
383 } | |
384 | |
385 static MapEntry[] entries(HotSpotOopMap fixedMap) { | |
386 MapEntry[] result = new MapEntry[fixedMap.size()]; | |
387 for (int idx = 0; idx < fixedMap.size(); idx++) { | |
388 MapEntry dstType = MapEntry.getFromBits(idx, fixedMap); | |
389 result[idx] = dstType; | |
390 } | |
391 return result; | |
392 } | |
393 | |
394 private static boolean verifyUpdate(HotSpotOopMap dst, HotSpotOopMap src) { | |
395 return verifyUpdate(dst, src, true); | |
396 } | |
397 | |
398 private static boolean verifyUpdate(HotSpotOopMap dst, HotSpotOopMap src, boolean doAssert) { | |
399 for (int idx = 0; idx < Math.min(src.size(), dst.size()); idx++) { | |
400 if (!verifyUpdateEntry(idx, dst, src, doAssert)) { | |
401 return false; | |
402 } | |
403 } | |
404 return true; | |
405 } | |
406 | |
407 private static boolean verifyUpdateEntry(int idx, HotSpotOopMap dst, HotSpotOopMap src, boolean doAssert) { | |
408 MapEntry dstType = MapEntry.getFromBits(idx, dst); | |
409 MapEntry srcType = MapEntry.getFromBits(idx, src); | |
410 | |
411 if (dstType == MapEntry.Illegal || srcType == MapEntry.Illegal) { | |
412 assert !doAssert : String.format("Illegal RefMap bit pattern: %s (0b%s), %s (0b%s)", dstType, dstType.toBitString(), srcType, srcType.toBitString()); | |
413 return false; | |
414 } | |
415 switch (dstType) { | |
416 case NoReference: | |
417 return true; | |
418 case WideOop: | |
419 switch (srcType) { | |
420 case NoReference: | |
421 case WideOop: | |
422 return true; | |
423 default: | |
424 assert false : String.format("Illegal RefMap combination: %s (0b%s), %s (0b%s)", dstType, dstType.toBitString(), srcType, srcType.toBitString()); | |
425 return false; | |
426 } | |
427 case TwoNarrowOops: | |
428 case NarrowOopLowerHalf: | |
429 case NarrowOopUpperHalf: | |
430 switch (srcType) { | |
431 case TwoNarrowOops: | |
432 case NarrowOopLowerHalf: | |
433 case NarrowOopUpperHalf: | |
434 case NoReference: | |
435 return true; | |
436 default: | |
437 assert false : String.format("Illegal RefMap combination: %s (0b%s), %s (0b%s)", dstType, dstType.toBitString(), srcType, srcType.toBitString()); | |
438 return false; | |
439 } | |
440 default: | |
441 return false; | |
442 } | |
443 } | 76 } |
444 | 77 |
445 @Override | 78 @Override |
446 public int hashCode() { | 79 public int hashCode() { |
447 throw new UnsupportedOperationException(); | 80 throw new UnsupportedOperationException(); |
452 if (this == obj) { | 85 if (this == obj) { |
453 return true; | 86 return true; |
454 } | 87 } |
455 if (obj instanceof HotSpotReferenceMap) { | 88 if (obj instanceof HotSpotReferenceMap) { |
456 HotSpotReferenceMap that = (HotSpotReferenceMap) obj; | 89 HotSpotReferenceMap that = (HotSpotReferenceMap) obj; |
457 if (this.frameRefMap.equals(that.frameRefMap) && Objects.equals(this.registerRefMap, that.registerRefMap) && this.target.equals(that.target)) { | 90 if (Arrays.equals(objects, that.objects) && this.target.equals(that.target)) { |
458 return true; | 91 return true; |
459 } | 92 } |
460 } | 93 } |
461 return false; | 94 return false; |
462 } | 95 } |
463 | 96 |
464 @Override | 97 @Override |
465 public boolean hasRegisterRefMap() { | |
466 return registerRefMap != null && registerRefMap.size() > 0; | |
467 } | |
468 | |
469 @Override | |
470 public boolean hasFrameRefMap() { | |
471 return frameRefMap != null && frameRefMap.size() > 0; | |
472 } | |
473 | |
474 @Override | |
475 public void appendRegisterMap(StringBuilder sb, RefMapFormatter formatter) { | |
476 for (int idx = 0; idx < registerRefMap.size(); idx++) { | |
477 MapEntry dstType = MapEntry.getFromBits(idx, registerRefMap); | |
478 if (dstType != MapEntry.NoReference) { | |
479 sb.append(' ').append(formatter.formatRegister(idx)).append(':').append(dstType); | |
480 } | |
481 } | |
482 } | |
483 | |
484 @Override | |
485 public void appendFrameMap(StringBuilder sb, RefMapFormatter formatter) { | |
486 for (int idx = 0; idx < frameRefMap.size(); idx++) { | |
487 MapEntry dstType = MapEntry.getFromBits(idx, frameRefMap); | |
488 if (dstType != MapEntry.NoReference) { | |
489 sb.append(' ').append(formatter.formatStackSlot(idx)).append(':').append(dstType); | |
490 } | |
491 } | |
492 } | |
493 | |
494 @Override | |
495 public String toString() { | 98 public String toString() { |
496 StringBuilder sb = new StringBuilder(); | 99 return Arrays.toString(objects); |
497 if (registerRefMap != null) { | |
498 sb.append("Registers = "); | |
499 sb.append(registerRefMap); | |
500 } | |
501 sb.append("Stack = "); | |
502 sb.append(frameRefMap); | |
503 return sb.toString(); | |
504 } | |
505 | |
506 public void verify() { | |
507 assert verifyUpdate(frameRefMap, frameRefMap); | |
508 assert registerRefMap == null || verifyUpdate(registerRefMap, registerRefMap); | |
509 } | 100 } |
510 } | 101 } |