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 }